diff --git a/.devcontainer.json b/.devcontainer.json
new file mode 100644
index 00000000000000..c0ae5292d6b572
--- /dev/null
+++ b/.devcontainer.json
@@ -0,0 +1,25 @@
+{
+ "name": "Node.js Core Developer Environment",
+ "runArgs": [
+ "--platform=linux/amd64"
+ ],
+ "customizations": {
+ "vscode": {
+ "extensions": [
+ "github.vscode-pull-request-github",
+ "ms-vsliveshare.vsliveshare",
+ "vscode-icons-team.vscode-icons",
+ "visualstudioexptteam.vscodeintellicode"
+ ],
+ "settings": {
+ "terminal.integrated.profiles.linux": {
+ "zsh (login)": {
+ "path": "zsh",
+ "args": ["-l"]
+ }
+ }
+ }
+ }
+ },
+ "image": "nodejs/devcontainer:nightly"
+}
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
deleted file mode 100644
index 75fda6e5b319b9..00000000000000
--- a/.devcontainer/devcontainer.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "Node.js Core Developer Environment",
- "extensions": [
- "github.vscode-pull-request-github",
- "ms-vsliveshare.vsliveshare",
- "vscode-icons-team.vscode-icons",
- "visualstudioexptteam.vscodeintellicode"
- ],
- "image": "nodejs/devcontainer:nightly",
- "settings": {
- "terminal.integrated.profiles.linux": {
- "zsh (login)": {
- "path": "zsh",
- "args": ["-l"]
- }
- }
- }
-}
diff --git a/.github/workflows/coverage-linux-without-intl.yml b/.github/workflows/coverage-linux-without-intl.yml
index c30ae78e303e07..6c44a51d81798c 100644
--- a/.github/workflows/coverage-linux-without-intl.yml
+++ b/.github/workflows/coverage-linux-without-intl.yml
@@ -79,6 +79,6 @@ jobs:
- name: Clean tmp
run: rm -rf coverage/tmp && rm -rf out
- name: Upload
- uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
+ uses: codecov/codecov-action@39a2af19d997be74586469d4062e173ecae614f6 # v5.4.3+
with:
directory: ./coverage
diff --git a/.github/workflows/coverage-linux.yml b/.github/workflows/coverage-linux.yml
index 6d5afb489762e4..6c1ef24648a85b 100644
--- a/.github/workflows/coverage-linux.yml
+++ b/.github/workflows/coverage-linux.yml
@@ -79,6 +79,6 @@ jobs:
- name: Clean tmp
run: rm -rf coverage/tmp && rm -rf out
- name: Upload
- uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
+ uses: codecov/codecov-action@39a2af19d997be74586469d4062e173ecae614f6 # v5.4.3+
with:
directory: ./coverage
diff --git a/.github/workflows/coverage-windows.yml b/.github/workflows/coverage-windows.yml
index 0e68565e962741..52facb5778fba1 100644
--- a/.github/workflows/coverage-windows.yml
+++ b/.github/workflows/coverage-windows.yml
@@ -71,6 +71,6 @@ jobs:
- name: Clean tmp
run: npx rimraf ./coverage/tmp
- name: Upload
- uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
+ uses: codecov/codecov-action@39a2af19d997be74586469d4062e173ecae614f6 # v5.4.3+
with:
directory: ./coverage
diff --git a/.gitignore b/.gitignore
index 60a3ff8b4a4cd8..90ebce4cb674ac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,8 +7,7 @@
.*
# Exclude specific dotfiles that we want to track.
!deps/**/.*
-!.devcontainer/
-!.devcontainer/.devcontainer.json
+!.devcontainer.json
!test/fixtures/**/.*
!.clang-format
!.cpplint
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f1983b2ddda791..843b312c289d76 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -40,7 +40,8 @@ release.
-24.6.0
+24.7.0
+24.6.0
24.5.0
24.4.1
24.4.0
diff --git a/SECURITY.md b/SECURITY.md
index d5cc79095371e3..9862585a92391c 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -102,6 +102,22 @@ vulnerability in the context of the Node.js threat model. In other
words, it cannot assume that a trusted element (such as the operating
system) has been compromised.
+### Experimental platforms
+
+Node.js maintains a tier-based support system for operating systems and
+hardware combinations (Tier 1, Tier 2, and Experimental). For platforms
+classified as "Experimental" in the [supported platforms](BUILDING.md#supported-platforms)
+documentation:
+
+* Security vulnerabilities that only affect experimental platforms will **not** be accepted as valid security issues.
+* Any issues on experimental platforms will be treated as normal bugs.
+* No CVEs will be issued for issues that only affect experimental platforms
+* Bug bounty rewards are not available for experimental platform-specific issues
+
+This policy recognizes that experimental platforms may not compile, may not
+pass the test suite, and do not have the same level of testing and support
+infrastructure as Tier 1 and Tier 2 platforms.
+
Being able to cause the following through control of the elements that Node.js
does not trust is considered a vulnerability:
@@ -284,3 +300,8 @@ Security notifications will be distributed via the following methods.
If you have suggestions on how this process could be improved, please visit
the [nodejs/security-wg](https://github.com/nodejs/security-wg)
repository.
+
+## Incident Response Plan
+
+In the event of a security incident, please refer to the
+[Security Incident Response Plan](https://github.com/nodejs/security-wg/blob/main/INCIDENT_RESPONSE_PLAN.md).
diff --git a/benchmark/common.js b/benchmark/common.js
index 0d3dbef24d07ad..0bb3fa3dfae32f 100644
--- a/benchmark/common.js
+++ b/benchmark/common.js
@@ -81,6 +81,9 @@ class Benchmark {
if (typeof value === 'number') {
if (key === 'dur' || key === 'duration') {
value = 0.05;
+ } else if (key === 'memory') {
+ // minimum Argon2 memcost with 1 lane is 8
+ value = 8;
} else if (value > 1) {
value = 1;
}
diff --git a/benchmark/crypto/argon2.js b/benchmark/crypto/argon2.js
new file mode 100644
index 00000000000000..ce6a824233e636
--- /dev/null
+++ b/benchmark/crypto/argon2.js
@@ -0,0 +1,53 @@
+'use strict';
+
+const common = require('../common.js');
+const { hasOpenSSL } = require('../../test/common/crypto.js');
+const assert = require('node:assert');
+const {
+ argon2,
+ argon2Sync,
+ randomBytes,
+} = require('node:crypto');
+
+if (!hasOpenSSL(3, 2)) {
+ console.log('Skipping: Argon2 requires OpenSSL >= 3.2');
+ process.exit(0);
+}
+
+const bench = common.createBenchmark(main, {
+ mode: ['sync', 'async'],
+ algorithm: ['argon2d', 'argon2i', 'argon2id'],
+ passes: [1, 3],
+ parallelism: [2, 4, 8],
+ memory: [2 ** 11, 2 ** 16, 2 ** 21],
+ n: [50],
+});
+
+function measureSync(n, algorithm, message, nonce, options) {
+ bench.start();
+ for (let i = 0; i < n; ++i)
+ argon2Sync(algorithm, { ...options, message, nonce, tagLength: 64 });
+ bench.end(n);
+}
+
+function measureAsync(n, algorithm, message, nonce, options) {
+ let remaining = n;
+ function done(err) {
+ assert.ifError(err);
+ if (--remaining === 0)
+ bench.end(n);
+ }
+ bench.start();
+ for (let i = 0; i < n; ++i)
+ argon2(algorithm, { ...options, message, nonce, tagLength: 64 }, done);
+}
+
+function main({ n, mode, algorithm, ...options }) {
+ // Message, nonce, secret, associated data & tag length do not affect performance
+ const message = randomBytes(32);
+ const nonce = randomBytes(16);
+ if (mode === 'sync')
+ measureSync(n, algorithm, message, nonce, options);
+ else
+ measureAsync(n, algorithm, message, nonce, options);
+}
diff --git a/benchmark/crypto/create-keyobject.js b/benchmark/crypto/create-keyobject.js
index 75988031abf6cc..58b873cde7f27a 100644
--- a/benchmark/crypto/create-keyobject.js
+++ b/benchmark/crypto/create-keyobject.js
@@ -1,6 +1,7 @@
'use strict';
const common = require('../common.js');
+const { hasOpenSSL } = require('../../test/common/crypto.js');
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
@@ -21,11 +22,14 @@ const keyFixtures = {
'ec': readKeyPair('ec_p256_public', 'ec_p256_private'),
'rsa': readKeyPair('rsa_public_2048', 'rsa_private_2048'),
'ed25519': readKeyPair('ed25519_public', 'ed25519_private'),
- 'ml-dsa-44': readKeyPair('ml_dsa_44_public', 'ml_dsa_44_private'),
};
+if (hasOpenSSL(3, 5)) {
+ keyFixtures['ml-dsa-44'] = readKeyPair('ml_dsa_44_public', 'ml_dsa_44_private');
+}
+
const bench = common.createBenchmark(main, {
- keyType: ['rsa', 'ec', 'ed25519', 'ml-dsa-44'],
+ keyType: Object.keys(keyFixtures),
keyFormat: ['pkcs8', 'spki', 'der-pkcs8', 'der-spki', 'jwk-public', 'jwk-private'],
n: [1e3],
});
diff --git a/benchmark/crypto/kem.js b/benchmark/crypto/kem.js
new file mode 100644
index 00000000000000..c36e79957a115c
--- /dev/null
+++ b/benchmark/crypto/kem.js
@@ -0,0 +1,140 @@
+'use strict';
+
+const common = require('../common.js');
+const { hasOpenSSL } = require('../../test/common/crypto.js');
+const crypto = require('crypto');
+const fs = require('fs');
+const path = require('path');
+const fixtures_keydir = path.resolve(__dirname, '../../test/fixtures/keys/');
+
+function readKey(name) {
+ return fs.readFileSync(`${fixtures_keydir}/${name}.pem`, 'utf8');
+}
+
+const keyFixtures = {};
+
+if (hasOpenSSL(3, 5)) {
+ keyFixtures['ml-kem-512'] = readKey('ml_kem_512_private');
+ keyFixtures['ml-kem-768'] = readKey('ml_kem_768_private');
+ keyFixtures['ml-kem-1024'] = readKey('ml_kem_1024_private');
+}
+if (hasOpenSSL(3, 2)) {
+ keyFixtures['p-256'] = readKey('ec_p256_private');
+ keyFixtures['p-384'] = readKey('ec_p384_private');
+ keyFixtures['p-521'] = readKey('ec_p521_private');
+ keyFixtures.x25519 = readKey('x25519_private');
+ keyFixtures.x448 = readKey('x448_private');
+}
+if (hasOpenSSL(3, 0)) {
+ keyFixtures.rsa = readKey('rsa_private_2048');
+}
+
+if (Object.keys(keyFixtures).length === 0) {
+ console.log('no supported key types available for this OpenSSL version');
+ process.exit(0);
+}
+
+const bench = common.createBenchmark(main, {
+ keyType: Object.keys(keyFixtures),
+ mode: ['sync', 'async', 'async-parallel'],
+ keyFormat: ['keyObject', 'keyObject.unique'],
+ op: ['encapsulate', 'decapsulate'],
+ n: [1e3],
+}, {
+ combinationFilter(p) {
+ // "keyObject.unique" allows to compare the result with "keyObject" to
+ // assess whether mutexes over the key material impact the operation
+ return p.keyFormat !== 'keyObject.unique' ||
+ (p.keyFormat === 'keyObject.unique' && p.mode === 'async-parallel');
+ },
+});
+
+function measureSync(n, op, privateKey, keys, ciphertexts) {
+ bench.start();
+ for (let i = 0; i < n; ++i) {
+ const key = privateKey || keys[i];
+ if (op === 'encapsulate') {
+ crypto.encapsulate(key);
+ } else {
+ crypto.decapsulate(key, ciphertexts[i]);
+ }
+ }
+ bench.end(n);
+}
+
+function measureAsync(n, op, privateKey, keys, ciphertexts) {
+ let remaining = n;
+ function done() {
+ if (--remaining === 0)
+ bench.end(n);
+ else
+ one();
+ }
+
+ function one() {
+ const key = privateKey || keys[n - remaining];
+ if (op === 'encapsulate') {
+ crypto.encapsulate(key, done);
+ } else {
+ crypto.decapsulate(key, ciphertexts[n - remaining], done);
+ }
+ }
+ bench.start();
+ one();
+}
+
+function measureAsyncParallel(n, op, privateKey, keys, ciphertexts) {
+ let remaining = n;
+ function done() {
+ if (--remaining === 0)
+ bench.end(n);
+ }
+ bench.start();
+ for (let i = 0; i < n; ++i) {
+ const key = privateKey || keys[i];
+ if (op === 'encapsulate') {
+ crypto.encapsulate(key, done);
+ } else {
+ crypto.decapsulate(key, ciphertexts[i], done);
+ }
+ }
+}
+
+function main({ n, mode, keyFormat, keyType, op }) {
+ const pems = [...Buffer.alloc(n)].map(() => keyFixtures[keyType]);
+ const keyObjects = pems.map(crypto.createPrivateKey);
+
+ let privateKey, keys, ciphertexts;
+
+ switch (keyFormat) {
+ case 'keyObject':
+ privateKey = keyObjects[0];
+ break;
+ case 'keyObject.unique':
+ keys = keyObjects;
+ break;
+ default:
+ throw new Error('not implemented');
+ }
+
+ // Pre-generate ciphertexts for decapsulate operations
+ if (op === 'decapsulate') {
+ if (privateKey) {
+ ciphertexts = [...Buffer.alloc(n)].map(() => crypto.encapsulate(privateKey).ciphertext);
+ } else {
+ ciphertexts = keys.map((key) => crypto.encapsulate(key).ciphertext);
+ }
+ }
+
+ switch (mode) {
+ case 'sync':
+ measureSync(n, op, privateKey, keys, ciphertexts);
+ break;
+ case 'async':
+ measureAsync(n, op, privateKey, keys, ciphertexts);
+ break;
+ case 'async-parallel':
+ measureAsyncParallel(n, op, privateKey, keys, ciphertexts);
+ break;
+ }
+}
diff --git a/benchmark/crypto/oneshot-sign.js b/benchmark/crypto/oneshot-sign.js
index 97372606a10ade..e1942c347d7508 100644
--- a/benchmark/crypto/oneshot-sign.js
+++ b/benchmark/crypto/oneshot-sign.js
@@ -1,6 +1,7 @@
'use strict';
const common = require('../common.js');
+const { hasOpenSSL } = require('../../test/common/crypto.js');
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
@@ -14,16 +15,19 @@ const keyFixtures = {
'ec': readKey('ec_p256_private'),
'rsa': readKey('rsa_private_2048'),
'ed25519': readKey('ed25519_private'),
- 'ml-dsa-44': readKey('ml_dsa_44_private'),
};
+if (hasOpenSSL(3, 5)) {
+ keyFixtures['ml-dsa-44'] = readKey('ml_dsa_44_private');
+}
+
const data = crypto.randomBytes(256);
let pems;
let keyObjects;
const bench = common.createBenchmark(main, {
- keyType: ['rsa', 'ec', 'ed25519', 'ml-dsa-44'],
+ keyType: Object.keys(keyFixtures),
mode: ['sync', 'async', 'async-parallel'],
keyFormat: ['pem', 'der', 'jwk', 'keyObject', 'keyObject.unique'],
n: [1e3],
diff --git a/benchmark/crypto/oneshot-verify.js b/benchmark/crypto/oneshot-verify.js
index 9569d5168f60ce..e0bbc0ce755f15 100644
--- a/benchmark/crypto/oneshot-verify.js
+++ b/benchmark/crypto/oneshot-verify.js
@@ -1,6 +1,7 @@
'use strict';
const common = require('../common.js');
+const { hasOpenSSL } = require('../../test/common/crypto.js');
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
@@ -21,16 +22,19 @@ const keyFixtures = {
'ec': readKeyPair('ec_p256_public', 'ec_p256_private'),
'rsa': readKeyPair('rsa_public_2048', 'rsa_private_2048'),
'ed25519': readKeyPair('ed25519_public', 'ed25519_private'),
- 'ml-dsa-44': readKeyPair('ml_dsa_44_public', 'ml_dsa_44_private'),
};
+if (hasOpenSSL(3, 5)) {
+ keyFixtures['ml-dsa-44'] = readKeyPair('ml_dsa_44_public', 'ml_dsa_44_private');
+}
+
const data = crypto.randomBytes(256);
let pems;
let keyObjects;
const bench = common.createBenchmark(main, {
- keyType: ['rsa', 'ec', 'ed25519', 'ml-dsa-44'],
+ keyType: Object.keys(keyFixtures),
mode: ['sync', 'async', 'async-parallel'],
keyFormat: ['pem', 'der', 'jwk', 'keyObject', 'keyObject.unique'],
n: [1e3],
diff --git a/benchmark/fs/readfile-permission-enabled.js b/benchmark/fs/readfile-permission-enabled.js
index c688e9eecb0e00..4d784ab343467a 100644
--- a/benchmark/fs/readfile-permission-enabled.js
+++ b/benchmark/fs/readfile-permission-enabled.js
@@ -12,8 +12,8 @@ const filename = tmpdir.resolve(`.removeme-benchmark-garbage-${process.pid}`);
const bench = common.createBenchmark(main, {
duration: [5],
- encoding: ['', 'utf-8'],
- len: [1024, 16 * 1024 * 1024],
+ encoding: ['utf-8'],
+ len: [1024],
concurrent: [1, 10],
}, {
flags: [
diff --git a/benchmark/http/bench-parser.js b/benchmark/http/bench-parser.js
index f2c120cd97f133..0a1e8f7b5e8a0f 100644
--- a/benchmark/http/bench-parser.js
+++ b/benchmark/http/bench-parser.js
@@ -16,7 +16,6 @@ function main({ len, n }) {
const kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0;
const kOnBody = HTTPParser.kOnBody | 0;
const kOnMessageComplete = HTTPParser.kOnMessageComplete | 0;
- const CRLF = '\r\n';
function processHeader(header, n) {
const parser = newParser(REQUEST);
@@ -43,12 +42,12 @@ function main({ len, n }) {
return parser;
}
- let header = `GET /hello HTTP/1.1${CRLF}Content-Type: text/plain${CRLF}`;
+ let header = `GET /hello HTTP/1.1\r\nContent-Type: text/plain\r\n`;
for (let i = 0; i < len; i++) {
- header += `X-Filler${i}: ${Math.random().toString(36).substring(2)}${CRLF}`;
+ header += `X-Filler${i}: ${Math.random().toString(36).substring(2)}\r\n`;
}
- header += CRLF;
+ header += '\r\n';
processHeader(Buffer.from(header), n);
}
diff --git a/benchmark/util/diff.js b/benchmark/util/diff.js
index 3ec024c24df6d0..7e40b3cd30f63b 100644
--- a/benchmark/util/diff.js
+++ b/benchmark/util/diff.js
@@ -5,7 +5,7 @@ const common = require('../common');
const bench = common.createBenchmark(main, {
n: [1e3],
- length: [1e3, 2e3],
+ length: [500, 1000],
scenario: ['identical', 'small-diff', 'medium-diff', 'large-diff'],
});
diff --git a/benchmark/v8/serialize.js b/benchmark/v8/serialize.js
index c370da49ea7cca..1b9a240bd458e4 100644
--- a/benchmark/v8/serialize.js
+++ b/benchmark/v8/serialize.js
@@ -4,8 +4,8 @@ const common = require('../common.js');
const v8 = require('v8');
const bench = common.createBenchmark(main, {
- len: [256, 1024 * 16, 1024 * 512],
- n: [1e6],
+ len: [256, 1024 * 16],
+ n: [1e5],
});
function main({ n, len }) {
diff --git a/common.gypi b/common.gypi
index 4a78c9029a4523..d4605a52de7db3 100644
--- a/common.gypi
+++ b/common.gypi
@@ -38,7 +38,7 @@
# Reset this number to 0 on major V8 upgrades.
# Increment by one for each non-official patch applied to deps/v8.
- 'v8_embedder_string': '-node.24',
+ 'v8_embedder_string': '-node.26',
##### V8 defaults for Node.js #####
@@ -538,7 +538,12 @@
'ldflags': [ '-m64' ],
}],
[ 'host_arch=="ppc64" and OS not in "aix os400"', {
- 'cflags': [ '-m64', '-mminimal-toc' ],
+ 'conditions': [
+ [ 'clang==0', {
+ 'cflags': [ '-mminimal-toc' ],
+ }],
+ ],
+ 'cflags': [ '-m64' ],
'ldflags': [ '-m64' ],
}],
[ 'host_arch=="s390x" and OS=="linux"', {
@@ -558,7 +563,12 @@
'ldflags': [ '-m64' ],
}],
[ 'target_arch=="ppc64" and OS not in "aix os400"', {
- 'cflags': [ '-m64', '-mminimal-toc' ],
+ 'conditions': [
+ [ 'clang==0', {
+ 'cflags': [ '-mminimal-toc' ],
+ }],
+ ],
+ 'cflags': [ '-m64' ],
'ldflags': [ '-m64' ],
}],
[ 'target_arch=="s390x" and OS=="linux"', {
diff --git a/configure.py b/configure.py
index c6e5154fde671d..b54a2f5961f9bc 100755
--- a/configure.py
+++ b/configure.py
@@ -1113,7 +1113,7 @@ def try_check_compiler(cc, lang):
proc = subprocess.Popen(shlex.split(cc) + ['-E', '-P', '-x', lang, '-'],
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
except OSError:
- return (False, False, '', '')
+ return (False, False, '', '', False)
with proc:
proc.stdin.write(b'__clang__ __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__ '
diff --git a/deps/ncrypto/ncrypto.cc b/deps/ncrypto/ncrypto.cc
index a2bfe874650fd5..73af3b8c37c073 100644
--- a/deps/ncrypto/ncrypto.cc
+++ b/deps/ncrypto/ncrypto.cc
@@ -10,7 +10,28 @@
#include
#include
#if OPENSSL_VERSION_MAJOR >= 3
+#include
+#include
#include
+#if OPENSSL_VERSION_NUMBER >= 0x30200000L
+#include
+#endif
+#endif
+#if OPENSSL_WITH_PQC
+struct PQCMapping {
+ const char* name;
+ int nid;
+};
+
+constexpr static PQCMapping pqc_mappings[] = {
+ {"ML-DSA-44", EVP_PKEY_ML_DSA_44},
+ {"ML-DSA-65", EVP_PKEY_ML_DSA_65},
+ {"ML-DSA-87", EVP_PKEY_ML_DSA_87},
+ {"ML-KEM-512", EVP_PKEY_ML_KEM_512},
+ {"ML-KEM-768", EVP_PKEY_ML_KEM_768},
+ {"ML-KEM-1024", EVP_PKEY_ML_KEM_1024},
+};
+
#endif
// EVP_PKEY_CTX_set_dsa_paramgen_q_bits was added in OpenSSL 1.1.1e.
@@ -1852,6 +1873,102 @@ DataPointer pbkdf2(const Digest& md,
return {};
}
+#if OPENSSL_VERSION_NUMBER >= 0x30200000L
+#ifndef OPENSSL_NO_ARGON2
+DataPointer argon2(const Buffer& pass,
+ const Buffer& salt,
+ uint32_t lanes,
+ size_t length,
+ uint32_t memcost,
+ uint32_t iter,
+ uint32_t version,
+ const Buffer& secret,
+ const Buffer& ad,
+ Argon2Type type) {
+ ClearErrorOnReturn clearErrorOnReturn;
+
+ std::string_view algorithm;
+ switch (type) {
+ case Argon2Type::ARGON2I:
+ algorithm = "ARGON2I";
+ break;
+ case Argon2Type::ARGON2D:
+ algorithm = "ARGON2D";
+ break;
+ case Argon2Type::ARGON2ID:
+ algorithm = "ARGON2ID";
+ break;
+ default:
+ // Invalid Argon2 type
+ return {};
+ }
+
+ // creates a new library context to avoid locking when running concurrently
+ auto ctx = DeleteFnPtr{OSSL_LIB_CTX_new()};
+ if (!ctx) {
+ return {};
+ }
+
+ // required if threads > 1
+ if (lanes > 1 && OSSL_set_max_threads(ctx.get(), lanes) != 1) {
+ return {};
+ }
+
+ auto kdf = DeleteFnPtr{
+ EVP_KDF_fetch(ctx.get(), algorithm.data(), nullptr)};
+ if (!kdf) {
+ return {};
+ }
+
+ auto kctx =
+ DeleteFnPtr{EVP_KDF_CTX_new(kdf.get())};
+ if (!kctx) {
+ return {};
+ }
+
+ std::vector params;
+ params.reserve(9);
+
+ params.push_back(OSSL_PARAM_construct_octet_string(
+ OSSL_KDF_PARAM_PASSWORD,
+ const_cast(pass.len > 0 ? pass.data : ""),
+ pass.len));
+ params.push_back(OSSL_PARAM_construct_octet_string(
+ OSSL_KDF_PARAM_SALT, const_cast(salt.data), salt.len));
+ params.push_back(OSSL_PARAM_construct_uint32(OSSL_KDF_PARAM_THREADS, &lanes));
+ params.push_back(
+ OSSL_PARAM_construct_uint32(OSSL_KDF_PARAM_ARGON2_LANES, &lanes));
+ params.push_back(
+ OSSL_PARAM_construct_uint32(OSSL_KDF_PARAM_ARGON2_MEMCOST, &memcost));
+ params.push_back(OSSL_PARAM_construct_uint32(OSSL_KDF_PARAM_ITER, &iter));
+
+ if (ad.len != 0) {
+ params.push_back(OSSL_PARAM_construct_octet_string(
+ OSSL_KDF_PARAM_ARGON2_AD, const_cast(ad.data), ad.len));
+ }
+
+ if (secret.len != 0) {
+ params.push_back(OSSL_PARAM_construct_octet_string(
+ OSSL_KDF_PARAM_SECRET,
+ const_cast(secret.data),
+ secret.len));
+ }
+
+ params.push_back(OSSL_PARAM_construct_end());
+
+ auto dp = DataPointer::Alloc(length);
+ if (dp && EVP_KDF_derive(kctx.get(),
+ reinterpret_cast(dp.get()),
+ length,
+ params.data()) == 1) {
+ return dp;
+ }
+
+ return {};
+}
+#endif
+#endif
+
// ============================================================================
EVPKeyPointer::PrivateKeyEncodingConfig::PrivateKeyEncodingConfig(
@@ -1897,7 +2014,7 @@ EVPKeyPointer EVPKeyPointer::NewRawPrivate(
EVP_PKEY_new_raw_private_key(id, nullptr, data.data, data.len));
}
-#if OPENSSL_VERSION_MAJOR >= 3 && OPENSSL_VERSION_MINOR >= 5
+#if OPENSSL_WITH_PQC
EVPKeyPointer EVPKeyPointer::NewRawSeed(
int id, const Buffer& data) {
if (id == 0) return {};
@@ -1968,12 +2085,22 @@ EVP_PKEY* EVPKeyPointer::release() {
int EVPKeyPointer::id(const EVP_PKEY* key) {
if (key == nullptr) return 0;
int type = EVP_PKEY_id(key);
-#if OPENSSL_VERSION_MAJOR >= 3 && OPENSSL_VERSION_MINOR >= 5
+#if OPENSSL_WITH_PQC
+ // EVP_PKEY_id returns -1 when EVP_PKEY_* is only implemented in a provider
+ // which is the case for all post-quantum NIST algorithms
+ // one suggested way would be to use a chain of `EVP_PKEY_is_a`
// https://github.com/openssl/openssl/issues/27738#issuecomment-3013215870
+ // or, this way there are less calls to the OpenSSL provider, just
+ // getting the name once
if (type == -1) {
- if (EVP_PKEY_is_a(key, "ML-DSA-44")) return EVP_PKEY_ML_DSA_44;
- if (EVP_PKEY_is_a(key, "ML-DSA-65")) return EVP_PKEY_ML_DSA_65;
- if (EVP_PKEY_is_a(key, "ML-DSA-87")) return EVP_PKEY_ML_DSA_87;
+ const char* type_name = EVP_PKEY_get0_type_name(key);
+ if (type_name == nullptr) return -1;
+
+ for (const auto& mapping : pqc_mappings) {
+ if (strcmp(type_name, mapping.name) == 0) {
+ return mapping.nid;
+ }
+ }
}
#endif
return type;
@@ -2032,24 +2159,37 @@ DataPointer EVPKeyPointer::rawPublicKey() const {
return {};
}
-#if OPENSSL_VERSION_MAJOR >= 3 && OPENSSL_VERSION_MINOR >= 5
+#if OPENSSL_WITH_PQC
DataPointer EVPKeyPointer::rawSeed() const {
if (!pkey_) return {};
+
+ // Determine seed length and parameter name based on key type
+ size_t seed_len;
+ const char* param_name;
+
switch (id()) {
case EVP_PKEY_ML_DSA_44:
case EVP_PKEY_ML_DSA_65:
case EVP_PKEY_ML_DSA_87:
+ seed_len = 32; // ML-DSA uses 32-byte seeds
+ param_name = OSSL_PKEY_PARAM_ML_DSA_SEED;
+ break;
+ case EVP_PKEY_ML_KEM_512:
+ case EVP_PKEY_ML_KEM_768:
+ case EVP_PKEY_ML_KEM_1024:
+ seed_len = 64; // ML-KEM uses 64-byte seeds
+ param_name = OSSL_PKEY_PARAM_ML_KEM_SEED;
break;
default:
unreachable();
}
- size_t seed_len = 32;
if (auto data = DataPointer::Alloc(seed_len)) {
const Buffer buf = data;
size_t len = data.size();
+
if (EVP_PKEY_get_octet_string_param(
- get(), OSSL_PKEY_PARAM_ML_DSA_SEED, buf.data, len, &seed_len) != 1)
+ get(), param_name, buf.data, len, &seed_len) != 1)
return {};
return data;
}
@@ -2515,7 +2655,7 @@ bool EVPKeyPointer::isOneShotVariant() const {
switch (type) {
case EVP_PKEY_ED25519:
case EVP_PKEY_ED448:
-#if OPENSSL_VERSION_MAJOR >= 3 && OPENSSL_VERSION_MINOR >= 5
+#if OPENSSL_WITH_PQC
case EVP_PKEY_ML_DSA_44:
case EVP_PKEY_ML_DSA_65:
case EVP_PKEY_ML_DSA_87:
@@ -2901,6 +3041,10 @@ const Cipher Cipher::AES_256_GCM = Cipher::FromNid(NID_aes_256_gcm);
const Cipher Cipher::AES_128_KW = Cipher::FromNid(NID_id_aes128_wrap);
const Cipher Cipher::AES_192_KW = Cipher::FromNid(NID_id_aes192_wrap);
const Cipher Cipher::AES_256_KW = Cipher::FromNid(NID_id_aes256_wrap);
+const Cipher Cipher::AES_128_OCB = Cipher::FromNid(NID_aes_128_ocb);
+const Cipher Cipher::AES_192_OCB = Cipher::FromNid(NID_aes_192_ocb);
+const Cipher Cipher::AES_256_OCB = Cipher::FromNid(NID_aes_256_ocb);
+const Cipher Cipher::CHACHA20_POLY1305 = Cipher::FromNid(NID_chacha20_poly1305);
bool Cipher::isGcmMode() const {
if (!cipher_) return false;
@@ -3102,6 +3246,11 @@ bool CipherCtxPointer::isGcmMode() const {
return getMode() == EVP_CIPH_GCM_MODE;
}
+bool CipherCtxPointer::isOcbMode() const {
+ if (!ctx_) return false;
+ return getMode() == EVP_CIPH_OCB_MODE;
+}
+
bool CipherCtxPointer::isCcmMode() const {
if (!ctx_) return false;
return getMode() == EVP_CIPH_CCM_MODE;
@@ -3617,7 +3766,6 @@ EVPKeyPointer EVPKeyCtxPointer::paramgen() const {
bool EVPKeyCtxPointer::publicCheck() const {
if (!ctx_) return false;
#ifndef OPENSSL_IS_BORINGSSL
- return EVP_PKEY_public_check(ctx_.get()) == 1;
#if OPENSSL_VERSION_MAJOR >= 3
return EVP_PKEY_public_check_quick(ctx_.get()) == 1;
#else
@@ -4383,4 +4531,125 @@ const Digest Digest::FromName(const char* name) {
return ncrypto::getDigestByName(name);
}
+// ============================================================================
+// KEM Implementation
+#if OPENSSL_VERSION_MAJOR >= 3
+#if !OPENSSL_VERSION_PREREQ(3, 5)
+bool KEM::SetOperationParameter(EVP_PKEY_CTX* ctx, const EVPKeyPointer& key) {
+ const char* operation = nullptr;
+
+ switch (EVP_PKEY_id(key.get())) {
+ case EVP_PKEY_RSA:
+ operation = OSSL_KEM_PARAM_OPERATION_RSASVE;
+ break;
+#if OPENSSL_VERSION_PREREQ(3, 2)
+ case EVP_PKEY_EC:
+ case EVP_PKEY_X25519:
+ case EVP_PKEY_X448:
+ operation = OSSL_KEM_PARAM_OPERATION_DHKEM;
+ break;
+#endif
+ default:
+ unreachable();
+ }
+
+ if (operation != nullptr) {
+ OSSL_PARAM params[] = {
+ OSSL_PARAM_utf8_string(
+ OSSL_KEM_PARAM_OPERATION, const_cast(operation), 0),
+ OSSL_PARAM_END};
+
+ if (EVP_PKEY_CTX_set_params(ctx, params) <= 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+#endif
+
+std::optional KEM::Encapsulate(
+ const EVPKeyPointer& public_key) {
+ ClearErrorOnReturn clear_error_on_return;
+
+ auto ctx = public_key.newCtx();
+ if (!ctx) return std::nullopt;
+
+ if (EVP_PKEY_encapsulate_init(ctx.get(), nullptr) <= 0) {
+ return std::nullopt;
+ }
+
+#if !OPENSSL_VERSION_PREREQ(3, 5)
+ if (!SetOperationParameter(ctx.get(), public_key)) {
+ return std::nullopt;
+ }
+#endif
+
+ // Determine output buffer sizes
+ size_t ciphertext_len = 0;
+ size_t shared_key_len = 0;
+
+ if (EVP_PKEY_encapsulate(
+ ctx.get(), nullptr, &ciphertext_len, nullptr, &shared_key_len) <= 0) {
+ return std::nullopt;
+ }
+
+ auto ciphertext = DataPointer::Alloc(ciphertext_len);
+ auto shared_key = DataPointer::Alloc(shared_key_len);
+ if (!ciphertext || !shared_key) return std::nullopt;
+
+ if (EVP_PKEY_encapsulate(ctx.get(),
+ static_cast(ciphertext.get()),
+ &ciphertext_len,
+ static_cast(shared_key.get()),
+ &shared_key_len) <= 0) {
+ return std::nullopt;
+ }
+
+ return EncapsulateResult(std::move(ciphertext), std::move(shared_key));
+}
+
+DataPointer KEM::Decapsulate(const EVPKeyPointer& private_key,
+ const Buffer& ciphertext) {
+ ClearErrorOnReturn clear_error_on_return;
+
+ auto ctx = private_key.newCtx();
+ if (!ctx) return {};
+
+ if (EVP_PKEY_decapsulate_init(ctx.get(), nullptr) <= 0) {
+ return {};
+ }
+
+#if !OPENSSL_VERSION_PREREQ(3, 5)
+ if (!SetOperationParameter(ctx.get(), private_key)) {
+ return {};
+ }
+#endif
+
+ // First pass: determine shared secret size
+ size_t shared_key_len = 0;
+ if (EVP_PKEY_decapsulate(ctx.get(),
+ nullptr,
+ &shared_key_len,
+ static_cast(ciphertext.data),
+ ciphertext.len) <= 0) {
+ return {};
+ }
+
+ auto shared_key = DataPointer::Alloc(shared_key_len);
+ if (!shared_key) return {};
+
+ if (EVP_PKEY_decapsulate(ctx.get(),
+ static_cast(shared_key.get()),
+ &shared_key_len,
+ static_cast(ciphertext.data),
+ ciphertext.len) <= 0) {
+ return {};
+ }
+
+ return shared_key;
+}
+
+#endif // OPENSSL_VERSION_MAJOR >= 3
+
} // namespace ncrypto
diff --git a/deps/ncrypto/ncrypto.h b/deps/ncrypto/ncrypto.h
index 82af70798f3171..6c62aa28a50e5a 100644
--- a/deps/ncrypto/ncrypto.h
+++ b/deps/ncrypto/ncrypto.h
@@ -28,11 +28,17 @@
#include
#endif // OPENSSL_FIPS
-#if OPENSSL_VERSION_MAJOR >= 3
-#define OSSL3_CONST const
-#if OPENSSL_VERSION_MINOR >= 5
+// Define OPENSSL_WITH_PQC for post-quantum cryptography support
+#if OPENSSL_VERSION_NUMBER >= 0x30500000L
+#define OPENSSL_WITH_PQC 1
+#define EVP_PKEY_ML_KEM_512 NID_ML_KEM_512
+#define EVP_PKEY_ML_KEM_768 NID_ML_KEM_768
+#define EVP_PKEY_ML_KEM_1024 NID_ML_KEM_1024
#include
#endif
+
+#if OPENSSL_VERSION_MAJOR >= 3
+#define OSSL3_CONST const
#else
#define OSSL3_CONST
#endif
@@ -367,6 +373,10 @@ class Cipher final {
static const Cipher AES_128_KW;
static const Cipher AES_192_KW;
static const Cipher AES_256_KW;
+ static const Cipher AES_128_OCB;
+ static const Cipher AES_192_OCB;
+ static const Cipher AES_256_OCB;
+ static const Cipher CHACHA20_POLY1305;
struct CipherParams {
int padding;
@@ -731,6 +741,7 @@ class CipherCtxPointer final {
int getNid() const;
bool isGcmMode() const;
+ bool isOcbMode() const;
bool isCcmMode() const;
bool isWrapMode() const;
bool isChaCha20Poly1305() const;
@@ -820,7 +831,7 @@ class EVPKeyPointer final {
const Buffer& data);
static EVPKeyPointer NewRawPrivate(int id,
const Buffer& data);
-#if OPENSSL_VERSION_MAJOR >= 3 && OPENSSL_VERSION_MINOR >= 5
+#if OPENSSL_WITH_PQC
static EVPKeyPointer NewRawSeed(int id,
const Buffer& data);
#endif
@@ -917,7 +928,7 @@ class EVPKeyPointer final {
DataPointer rawPrivateKey() const;
BIOPointer derPublicKey() const;
-#if OPENSSL_VERSION_MAJOR >= 3 && OPENSSL_VERSION_MINOR >= 5
+#if OPENSSL_WITH_PQC
DataPointer rawSeed() const;
#endif
@@ -1550,6 +1561,57 @@ DataPointer pbkdf2(const Digest& md,
uint32_t iterations,
size_t length);
+#if OPENSSL_VERSION_NUMBER >= 0x30200000L
+#ifndef OPENSSL_NO_ARGON2
+enum class Argon2Type { ARGON2D, ARGON2I, ARGON2ID };
+
+DataPointer argon2(const Buffer& pass,
+ const Buffer& salt,
+ uint32_t lanes,
+ size_t length,
+ uint32_t memcost,
+ uint32_t iter,
+ uint32_t version,
+ const Buffer& secret,
+ const Buffer& ad,
+ Argon2Type type);
+#endif
+#endif
+
+// ============================================================================
+// KEM (Key Encapsulation Mechanism)
+#if OPENSSL_VERSION_MAJOR >= 3
+
+class KEM final {
+ public:
+ struct EncapsulateResult {
+ DataPointer ciphertext;
+ DataPointer shared_key;
+
+ EncapsulateResult() = default;
+ EncapsulateResult(DataPointer ct, DataPointer sk)
+ : ciphertext(std::move(ct)), shared_key(std::move(sk)) {}
+ };
+
+ // Encapsulate a shared secret using KEM with a public key.
+ // Returns both the ciphertext and shared secret.
+ static std::optional Encapsulate(
+ const EVPKeyPointer& public_key);
+
+ // Decapsulate a shared secret using KEM with a private key and ciphertext.
+ // Returns the shared secret.
+ static DataPointer Decapsulate(const EVPKeyPointer& private_key,
+ const Buffer& ciphertext);
+
+ private:
+#if !OPENSSL_VERSION_PREREQ(3, 5)
+ static bool SetOperationParameter(EVP_PKEY_CTX* ctx,
+ const EVPKeyPointer& key);
+#endif
+};
+
+#endif // OPENSSL_VERSION_MAJOR >= 3
+
// ============================================================================
// Version metadata
#define NCRYPTO_VERSION "0.0.1"
diff --git a/deps/undici/src/README.md b/deps/undici/src/README.md
index 93008eb09918d9..eb69c0ca8f4a5a 100644
--- a/deps/undici/src/README.md
+++ b/deps/undici/src/README.md
@@ -622,11 +622,11 @@ and `undici.Agent`) which will enable the family autoselection algorithm when es
Undici aligns with the Node.js LTS schedule. The following table shows the supported versions:
-| Version | Node.js | End of Life |
-|---------|-------------|-------------|
-| 5.x | v18.x | 2024-04-30 |
-| 6.x | v20.x v22.x | 2026-04-30 |
-| 7.x | v24.x | 2027-04-30 |
+| Undici Version | Bundled in Node.js | Node.js Versions Supported | End of Life |
+|----------------|-------------------|----------------------------|-------------|
+| 5.x | 18.x | ≥14.0 (tested: 14, 16, 18) | 2024-04-30 |
+| 6.x | 20.x, 22.x | ≥18.17 (tested: 18, 20, 21, 22) | 2026-04-30 |
+| 7.x | 24.x | ≥20.18.1 (tested: 20, 22, 24) | 2027-04-30 |
## License
diff --git a/deps/undici/src/docs/docs/api/DiagnosticsChannel.md b/deps/undici/src/docs/docs/api/DiagnosticsChannel.md
index dab13a7df6edb3..096bd58ce29882 100644
--- a/deps/undici/src/docs/docs/api/DiagnosticsChannel.md
+++ b/deps/undici/src/docs/docs/api/DiagnosticsChannel.md
@@ -169,14 +169,38 @@ This message is published after the client has successfully connected to a serve
```js
import diagnosticsChannel from 'diagnostics_channel'
-diagnosticsChannel.channel('undici:websocket:open').subscribe(({ address, protocol, extensions, websocket }) => {
+diagnosticsChannel.channel('undici:websocket:open').subscribe(({
+ address, // { address: string, family: string, port: number }
+ protocol, // string - negotiated subprotocol
+ extensions, // string - negotiated extensions
+ websocket, // WebSocket - the WebSocket instance
+ handshakeResponse // object - HTTP response that upgraded the connection
+}) => {
console.log(address) // address, family, and port
console.log(protocol) // negotiated subprotocols
console.log(extensions) // negotiated extensions
console.log(websocket) // the WebSocket instance
+
+ // Handshake response details
+ console.log(handshakeResponse.status) // 101 for successful WebSocket upgrade
+ console.log(handshakeResponse.statusText) // 'Switching Protocols'
+ console.log(handshakeResponse.headers) // Object containing response headers
})
```
+### Handshake Response Object
+
+The `handshakeResponse` object contains the HTTP response that upgraded the connection to WebSocket:
+
+- `status` (number): The HTTP status code (101 for successful WebSocket upgrade)
+- `statusText` (string): The HTTP status message ('Switching Protocols' for successful upgrade)
+- `headers` (object): The HTTP response headers from the server, including:
+ - `upgrade: 'websocket'`
+ - `connection: 'upgrade'`
+ - `sec-websocket-accept` and other WebSocket-related headers
+
+This information is particularly useful for debugging and monitoring WebSocket connections, as it provides access to the initial HTTP handshake response that established the WebSocket connection.
+
## `undici:websocket:close`
This message is published after the connection has closed.
diff --git a/deps/undici/src/lib/dispatcher/proxy-agent.js b/deps/undici/src/lib/dispatcher/proxy-agent.js
index 139ae6d17274d5..f0a71f7adbfb75 100644
--- a/deps/undici/src/lib/dispatcher/proxy-agent.js
+++ b/deps/undici/src/lib/dispatcher/proxy-agent.js
@@ -1,7 +1,6 @@
'use strict'
const { kProxy, kClose, kDestroy, kDispatch } = require('../core/symbols')
-const { URL } = require('node:url')
const Agent = require('./agent')
const Pool = require('./pool')
const DispatcherBase = require('./dispatcher-base')
@@ -208,7 +207,7 @@ class ProxyAgent extends DispatcherBase {
}
/**
- * @param {import('../types/proxy-agent').ProxyAgent.Options | string | URL} opts
+ * @param {import('../../types/proxy-agent').ProxyAgent.Options | string | URL} opts
* @returns {URL}
*/
#getUrl (opts) {
diff --git a/deps/undici/src/lib/handler/cache-handler.js b/deps/undici/src/lib/handler/cache-handler.js
index 937790aca12292..c21a7206551660 100644
--- a/deps/undici/src/lib/handler/cache-handler.js
+++ b/deps/undici/src/lib/handler/cache-handler.js
@@ -15,6 +15,15 @@ const HEURISTICALLY_CACHEABLE_STATUS_CODES = [
200, 203, 204, 206, 300, 301, 308, 404, 405, 410, 414, 501
]
+// Status codes which semantic is not handled by the cache
+// https://datatracker.ietf.org/doc/html/rfc9111#section-3
+// This list should not grow beyond 206 and 304 unless the RFC is updated
+// by a newer one including more. Please introduce another list if
+// implementing caching of responses with the 'must-understand' directive.
+const NOT_UNDERSTOOD_STATUS_CODES = [
+ 206, 304
+]
+
const MAX_RESPONSE_AGE = 2147483647000
/**
@@ -241,10 +250,19 @@ class CacheHandler {
* @param {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives} cacheControlDirectives
*/
function canCacheResponse (cacheType, statusCode, resHeaders, cacheControlDirectives) {
- // Allow caching for status codes 200 and 307 (original behavior)
- // Also allow caching for other status codes that are heuristically cacheable
- // when they have explicit cache directives
- if (statusCode !== 200 && statusCode !== 307 && !HEURISTICALLY_CACHEABLE_STATUS_CODES.includes(statusCode)) {
+ // Status code must be final and understood.
+ if (statusCode < 200 || NOT_UNDERSTOOD_STATUS_CODES.includes(statusCode)) {
+ return false
+ }
+ // Responses with neither status codes that are heuristically cacheable, nor "explicit enough" caching
+ // directives, are not cacheable. "Explicit enough": see https://www.rfc-editor.org/rfc/rfc9111.html#section-3
+ if (!HEURISTICALLY_CACHEABLE_STATUS_CODES.includes(statusCode) && !resHeaders['expires'] &&
+ !cacheControlDirectives.public &&
+ cacheControlDirectives['max-age'] === undefined &&
+ // RFC 9111: a private response directive, if the cache is not shared
+ !(cacheControlDirectives.private && cacheType === 'private') &&
+ !(cacheControlDirectives['s-maxage'] !== undefined && cacheType === 'shared')
+ ) {
return false
}
diff --git a/deps/undici/src/lib/interceptor/cache.js b/deps/undici/src/lib/interceptor/cache.js
index a2f235b8db34e4..6565baf0a51014 100644
--- a/deps/undici/src/lib/interceptor/cache.js
+++ b/deps/undici/src/lib/interceptor/cache.js
@@ -6,7 +6,7 @@ const util = require('../core/util')
const CacheHandler = require('../handler/cache-handler')
const MemoryCacheStore = require('../cache/memory-cache-store')
const CacheRevalidationHandler = require('../handler/cache-revalidation-handler')
-const { assertCacheStore, assertCacheMethods, makeCacheKey, normaliseHeaders, parseCacheControlHeader } = require('../util/cache.js')
+const { assertCacheStore, assertCacheMethods, makeCacheKey, normalizeHeaders, parseCacheControlHeader } = require('../util/cache.js')
const { AbortError } = require('../core/errors.js')
/**
@@ -326,7 +326,7 @@ module.exports = (opts = {}) => {
opts = {
...opts,
- headers: normaliseHeaders(opts)
+ headers: normalizeHeaders(opts)
}
const reqCacheControl = opts.headers?.['cache-control']
diff --git a/deps/undici/src/lib/llhttp/wasm_build_env.txt b/deps/undici/src/lib/llhttp/wasm_build_env.txt
index 77e7ad40adc06a..ecb13a031dc5c8 100644
--- a/deps/undici/src/lib/llhttp/wasm_build_env.txt
+++ b/deps/undici/src/lib/llhttp/wasm_build_env.txt
@@ -1,5 +1,5 @@
-> undici@7.13.0 build:wasm
+> undici@7.14.0 build:wasm
> node build/wasm.js --docker
> docker run --rm --platform=linux/x86_64 --user 1001:118 --mount type=bind,source=/home/runner/work/node/node/deps/undici/src/lib/llhttp,target=/home/node/build/lib/llhttp --mount type=bind,source=/home/runner/work/node/node/deps/undici/src/build,target=/home/node/build/build --mount type=bind,source=/home/runner/work/node/node/deps/undici/src/deps,target=/home/node/build/deps -t ghcr.io/nodejs/wasm-builder@sha256:975f391d907e42a75b8c72eb77c782181e941608687d4d8694c3e9df415a0970 node build/wasm.js
diff --git a/deps/undici/src/lib/mock/snapshot-agent.js b/deps/undici/src/lib/mock/snapshot-agent.js
index abdd8227e1e367..dbe53575f1d4e8 100644
--- a/deps/undici/src/lib/mock/snapshot-agent.js
+++ b/deps/undici/src/lib/mock/snapshot-agent.js
@@ -5,6 +5,7 @@ const MockAgent = require('./mock-agent')
const { SnapshotRecorder } = require('./snapshot-recorder')
const WrapHandler = require('../handler/wrap-handler')
const { InvalidArgumentError, UndiciError } = require('../core/errors')
+const { validateSnapshotMode } = require('./snapshot-utils')
const kSnapshotRecorder = Symbol('kSnapshotRecorder')
const kSnapshotMode = Symbol('kSnapshotMode')
@@ -12,7 +13,7 @@ const kSnapshotPath = Symbol('kSnapshotPath')
const kSnapshotLoaded = Symbol('kSnapshotLoaded')
const kRealAgent = Symbol('kRealAgent')
-// Static flag to ensure warning is only emitted once
+// Static flag to ensure warning is only emitted once per process
let warningEmitted = false
class SnapshotAgent extends MockAgent {
@@ -26,26 +27,24 @@ class SnapshotAgent extends MockAgent {
warningEmitted = true
}
- const mockOptions = { ...opts }
- delete mockOptions.mode
- delete mockOptions.snapshotPath
+ const {
+ mode = 'record',
+ snapshotPath = null,
+ ...mockAgentOpts
+ } = opts
- super(mockOptions)
+ super(mockAgentOpts)
- // Validate mode option
- const validModes = ['record', 'playback', 'update']
- const mode = opts.mode || 'record'
- if (!validModes.includes(mode)) {
- throw new InvalidArgumentError(`Invalid snapshot mode: ${mode}. Must be one of: ${validModes.join(', ')}`)
- }
+ validateSnapshotMode(mode)
// Validate snapshotPath is provided when required
- if ((mode === 'playback' || mode === 'update') && !opts.snapshotPath) {
+ if ((mode === 'playback' || mode === 'update') && !snapshotPath) {
throw new InvalidArgumentError(`snapshotPath is required when mode is '${mode}'`)
}
this[kSnapshotMode] = mode
- this[kSnapshotPath] = opts.snapshotPath
+ this[kSnapshotPath] = snapshotPath
+
this[kSnapshotRecorder] = new SnapshotRecorder({
snapshotPath: this[kSnapshotPath],
mode: this[kSnapshotMode],
@@ -85,7 +84,7 @@ class SnapshotAgent extends MockAgent {
// Ensure snapshots are loaded
if (!this[kSnapshotLoaded]) {
// Need to load asynchronously, delegate to async version
- return this._asyncDispatch(opts, handler)
+ return this.#asyncDispatch(opts, handler)
}
// Try to find existing snapshot (synchronous)
@@ -93,10 +92,10 @@ class SnapshotAgent extends MockAgent {
if (snapshot) {
// Use recorded response (synchronous)
- return this._replaySnapshot(snapshot, handler)
+ return this.#replaySnapshot(snapshot, handler)
} else if (mode === 'update') {
// Make real request and record it (async required)
- return this._recordAndReplay(opts, handler)
+ return this.#recordAndReplay(opts, handler)
} else {
// Playback mode but no snapshot found
const error = new UndiciError(`No snapshot found for ${opts.method || 'GET'} ${opts.path}`)
@@ -108,16 +107,14 @@ class SnapshotAgent extends MockAgent {
}
} else if (mode === 'record') {
// Record mode - make real request and save response (async required)
- return this._recordAndReplay(opts, handler)
- } else {
- throw new InvalidArgumentError(`Invalid snapshot mode: ${mode}. Must be 'record', 'playback', or 'update'`)
+ return this.#recordAndReplay(opts, handler)
}
}
/**
* Async version of dispatch for when we need to load snapshots first
*/
- async _asyncDispatch (opts, handler) {
+ async #asyncDispatch (opts, handler) {
await this.loadSnapshots()
return this.dispatch(opts, handler)
}
@@ -125,7 +122,7 @@ class SnapshotAgent extends MockAgent {
/**
* Records a real request and replays the response
*/
- _recordAndReplay (opts, handler) {
+ #recordAndReplay (opts, handler) {
const responseData = {
statusCode: null,
headers: {},
@@ -180,45 +177,46 @@ class SnapshotAgent extends MockAgent {
/**
* Replays a recorded response
+ *
+ * @param {Object} snapshot - The recorded snapshot to replay.
+ * @param {Object} handler - The handler to call with the response data.
+ * @returns {void}
*/
- _replaySnapshot (snapshot, handler) {
- return new Promise((resolve) => {
- // Simulate the response
- setImmediate(() => {
- try {
- const { response } = snapshot
-
- const controller = {
- pause () {},
- resume () {},
- abort (reason) {
- this.aborted = true
- this.reason = reason
- },
-
- aborted: false,
- paused: false
- }
-
- handler.onRequestStart(controller)
-
- handler.onResponseStart(controller, response.statusCode, response.headers)
-
- // Body is always stored as base64 string
- const body = Buffer.from(response.body, 'base64')
- handler.onResponseData(controller, body)
-
- handler.onResponseEnd(controller, response.trailers)
- resolve()
- } catch (error) {
- handler.onError?.(error)
- }
- })
- })
+ #replaySnapshot (snapshot, handler) {
+ try {
+ const { response } = snapshot
+
+ const controller = {
+ pause () { },
+ resume () { },
+ abort (reason) {
+ this.aborted = true
+ this.reason = reason
+ },
+
+ aborted: false,
+ paused: false
+ }
+
+ handler.onRequestStart(controller)
+
+ handler.onResponseStart(controller, response.statusCode, response.headers)
+
+ // Body is always stored as base64 string
+ const body = Buffer.from(response.body, 'base64')
+ handler.onResponseData(controller, body)
+
+ handler.onResponseEnd(controller, response.trailers)
+ } catch (error) {
+ handler.onError?.(error)
+ }
}
/**
* Loads snapshots from file
+ *
+ * @param {string} [filePath] - Optional file path to load snapshots from.
+ * @returns {Promise} - Resolves when snapshots are loaded.
*/
async loadSnapshots (filePath) {
await this[kSnapshotRecorder].loadSnapshots(filePath || this[kSnapshotPath])
@@ -226,12 +224,15 @@ class SnapshotAgent extends MockAgent {
// In playback mode, set up MockAgent interceptors for all snapshots
if (this[kSnapshotMode] === 'playback') {
- this._setupMockInterceptors()
+ this.#setupMockInterceptors()
}
}
/**
* Saves snapshots to file
+ *
+ * @param {string} [filePath] - Optional file path to save snapshots to.
+ * @returns {Promise} - Resolves when snapshots are saved.
*/
async saveSnapshots (filePath) {
return this[kSnapshotRecorder].saveSnapshots(filePath || this[kSnapshotPath])
@@ -248,9 +249,9 @@ class SnapshotAgent extends MockAgent {
*
* Called automatically when loading snapshots in playback mode.
*
- * @private
+ * @returns {void}
*/
- _setupMockInterceptors () {
+ #setupMockInterceptors () {
for (const snapshot of this[kSnapshotRecorder].getSnapshots()) {
const { request, responses, response } = snapshot
const url = new URL(request.url)
@@ -275,6 +276,7 @@ class SnapshotAgent extends MockAgent {
/**
* Gets the snapshot recorder
+ * @return {SnapshotRecorder} - The snapshot recorder instance
*/
getRecorder () {
return this[kSnapshotRecorder]
@@ -282,6 +284,7 @@ class SnapshotAgent extends MockAgent {
/**
* Gets the current mode
+ * @return {import('./snapshot-utils').SnapshotMode} - The current snapshot mode
*/
getMode () {
return this[kSnapshotMode]
@@ -289,6 +292,7 @@ class SnapshotAgent extends MockAgent {
/**
* Clears all snapshots
+ * @returns {void}
*/
clearSnapshots () {
this[kSnapshotRecorder].clear()
@@ -296,6 +300,7 @@ class SnapshotAgent extends MockAgent {
/**
* Resets call counts for all snapshots (useful for test cleanup)
+ * @returns {void}
*/
resetCallCounts () {
this[kSnapshotRecorder].resetCallCounts()
@@ -303,6 +308,8 @@ class SnapshotAgent extends MockAgent {
/**
* Deletes a specific snapshot by request options
+ * @param {import('./snapshot-recorder').SnapshotRequestOptions} requestOpts - Request options to identify the snapshot
+ * @return {Promise} - Returns true if the snapshot was deleted, false if not found
*/
deleteSnapshot (requestOpts) {
return this[kSnapshotRecorder].deleteSnapshot(requestOpts)
@@ -310,6 +317,7 @@ class SnapshotAgent extends MockAgent {
/**
* Gets information about a specific snapshot
+ * @returns {import('./snapshot-recorder').SnapshotInfo|null} - Snapshot information or null if not found
*/
getSnapshotInfo (requestOpts) {
return this[kSnapshotRecorder].getSnapshotInfo(requestOpts)
@@ -317,13 +325,19 @@ class SnapshotAgent extends MockAgent {
/**
* Replaces all snapshots with new data (full replacement)
+ * @param {Array<{hash: string; snapshot: import('./snapshot-recorder').SnapshotEntryshotEntry}>|Record} snapshotData - New snapshot data to replace existing snapshots
+ * @returns {void}
*/
replaceSnapshots (snapshotData) {
this[kSnapshotRecorder].replaceSnapshots(snapshotData)
}
+ /**
+ * Closes the agent, saving snapshots and cleaning up resources.
+ *
+ * @returns {Promise}
+ */
async close () {
- // Close recorder (saves snapshots and cleans up timers)
await this[kSnapshotRecorder].close()
await this[kRealAgent]?.close()
await super.close()
diff --git a/deps/undici/src/lib/mock/snapshot-recorder.js b/deps/undici/src/lib/mock/snapshot-recorder.js
index 7482b5c1914a56..e810fe795072a7 100644
--- a/deps/undici/src/lib/mock/snapshot-recorder.js
+++ b/deps/undici/src/lib/mock/snapshot-recorder.js
@@ -2,13 +2,93 @@
const { writeFile, readFile, mkdir } = require('node:fs/promises')
const { dirname, resolve } = require('node:path')
+const { setTimeout, clearTimeout } = require('node:timers')
const { InvalidArgumentError, UndiciError } = require('../core/errors')
+const { hashId, isUrlExcludedFactory, normalizeHeaders, createHeaderFilters } = require('./snapshot-utils')
+
+/**
+ * @typedef {Object} SnapshotRequestOptions
+ * @property {string} method - HTTP method (e.g. 'GET', 'POST', etc.)
+ * @property {string} path - Request path
+ * @property {string} origin - Request origin (base URL)
+ * @property {import('./snapshot-utils').Headers|import('./snapshot-utils').UndiciHeaders} headers - Request headers
+ * @property {import('./snapshot-utils').NormalizedHeaders} _normalizedHeaders - Request headers as a lowercase object
+ * @property {string|Buffer} [body] - Request body (optional)
+ */
+
+/**
+ * @typedef {Object} SnapshotEntryRequest
+ * @property {string} method - HTTP method (e.g. 'GET', 'POST', etc.)
+ * @property {string} url - Full URL of the request
+ * @property {import('./snapshot-utils').NormalizedHeaders} headers - Normalized headers as a lowercase object
+ * @property {string|Buffer} [body] - Request body (optional)
+ */
+
+/**
+ * @typedef {Object} SnapshotEntryResponse
+ * @property {number} statusCode - HTTP status code of the response
+ * @property {import('./snapshot-utils').NormalizedHeaders} headers - Normalized response headers as a lowercase object
+ * @property {string} body - Response body as a base64url encoded string
+ * @property {Object} [trailers] - Optional response trailers
+ */
+
+/**
+ * @typedef {Object} SnapshotEntry
+ * @property {SnapshotEntryRequest} request - The request object
+ * @property {Array} responses - Array of response objects
+ * @property {number} callCount - Number of times this snapshot has been called
+ * @property {string} timestamp - ISO timestamp of when the snapshot was created
+ */
+
+/**
+ * @typedef {Object} SnapshotRecorderMatchOptions
+ * @property {Array} [matchHeaders=[]] - Headers to match (empty array means match all headers)
+ * @property {Array} [ignoreHeaders=[]] - Headers to ignore for matching
+ * @property {Array} [excludeHeaders=[]] - Headers to exclude from matching
+ * @property {boolean} [matchBody=true] - Whether to match request body
+ * @property {boolean} [matchQuery=true] - Whether to match query properties
+ * @property {boolean} [caseSensitive=false] - Whether header matching is case-sensitive
+ */
+
+/**
+ * @typedef {Object} SnapshotRecorderOptions
+ * @property {string} [snapshotPath] - Path to save/load snapshots
+ * @property {import('./snapshot-utils').SnapshotMode} [mode='record'] - Mode: 'record' or 'playback'
+ * @property {number} [maxSnapshots=Infinity] - Maximum number of snapshots to keep
+ * @property {boolean} [autoFlush=false] - Whether to automatically flush snapshots to disk
+ * @property {number} [flushInterval=30000] - Auto-flush interval in milliseconds (default: 30 seconds)
+ * @property {Array} [excludeUrls=[]] - URLs to exclude from recording
+ * @property {function} [shouldRecord=null] - Function to filter requests for recording
+ * @property {function} [shouldPlayback=null] - Function to filter requests
+ */
+
+/**
+ * @typedef {Object} SnapshotFormattedRequest
+ * @property {string} method - HTTP method (e.g. 'GET', 'POST', etc.)
+ * @property {string} url - Full URL of the request (with query parameters if matchQuery is true)
+ * @property {import('./snapshot-utils').NormalizedHeaders} headers - Normalized headers as a lowercase object
+ * @property {string} body - Request body (optional, only if matchBody is true)
+ */
+
+/**
+ * @typedef {Object} SnapshotInfo
+ * @property {string} hash - Hash key for the snapshot
+ * @property {SnapshotEntryRequest} request - The request object
+ * @property {number} responseCount - Number of responses recorded for this request
+ * @property {number} callCount - Number of times this snapshot has been called
+ * @property {string} timestamp - ISO timestamp of when the snapshot was created
+ */
/**
* Formats a request for consistent snapshot storage
* Caches normalized headers to avoid repeated processing
+ *
+ * @param {SnapshotRequestOptions} opts - Request options
+ * @param {import('./snapshot-utils').HeaderFilters} headerFilters - Cached header sets for performance
+ * @param {SnapshotRecorderMatchOptions} [matchOptions] - Matching options for headers and body
+ * @returns {SnapshotFormattedRequest} - Formatted request object
*/
-function formatRequestKey (opts, cachedSets, matchOptions = {}) {
+function formatRequestKey (opts, headerFilters, matchOptions = {}) {
const url = new URL(opts.path, opts.origin)
// Cache normalized headers if not already done
@@ -20,37 +100,40 @@ function formatRequestKey (opts, cachedSets, matchOptions = {}) {
return {
method: opts.method || 'GET',
url: matchOptions.matchQuery !== false ? url.toString() : `${url.origin}${url.pathname}`,
- headers: filterHeadersForMatching(normalized, cachedSets, matchOptions),
- body: matchOptions.matchBody !== false && opts.body ? String(opts.body) : undefined
+ headers: filterHeadersForMatching(normalized, headerFilters, matchOptions),
+ body: matchOptions.matchBody !== false && opts.body ? String(opts.body) : ''
}
}
/**
* Filters headers based on matching configuration
+ *
+ * @param {import('./snapshot-utils').Headers} headers - Headers to filter
+ * @param {import('./snapshot-utils').HeaderFilters} headerFilters - Cached sets for ignore, exclude, and match headers
+ * @param {SnapshotRecorderMatchOptions} [matchOptions] - Matching options for headers
*/
-function filterHeadersForMatching (headers, cachedSets, matchOptions = {}) {
+function filterHeadersForMatching (headers, headerFilters, matchOptions = {}) {
if (!headers || typeof headers !== 'object') return {}
const {
- matchHeaders = null,
caseSensitive = false
} = matchOptions
const filtered = {}
- const { ignoreSet, excludeSet, matchSet } = cachedSets
+ const { ignore, exclude, match } = headerFilters
for (const [key, value] of Object.entries(headers)) {
const headerKey = caseSensitive ? key : key.toLowerCase()
// Skip if in exclude list (for security)
- if (excludeSet.has(headerKey)) continue
+ if (exclude.has(headerKey)) continue
// Skip if in ignore list (for matching)
- if (ignoreSet.has(headerKey)) continue
+ if (ignore.has(headerKey)) continue
// If matchHeaders is specified, only include those headers
- if (matchHeaders && Array.isArray(matchHeaders)) {
- if (!matchSet.has(headerKey)) continue
+ if (match.size !== 0) {
+ if (!match.has(headerKey)) continue
}
filtered[headerKey] = value
@@ -61,17 +144,20 @@ function filterHeadersForMatching (headers, cachedSets, matchOptions = {}) {
/**
* Filters headers for storage (only excludes sensitive headers)
+ *
+ * @param {import('./snapshot-utils').Headers} headers - Headers to filter
+ * @param {import('./snapshot-utils').HeaderFilters} headerFilters - Cached sets for ignore, exclude, and match headers
+ * @param {SnapshotRecorderMatchOptions} [matchOptions] - Matching options for headers
*/
-function filterHeadersForStorage (headers, matchOptions = {}) {
+function filterHeadersForStorage (headers, headerFilters, matchOptions = {}) {
if (!headers || typeof headers !== 'object') return {}
const {
- excludeHeaders = [],
caseSensitive = false
} = matchOptions
const filtered = {}
- const excludeSet = new Set(excludeHeaders.map(h => caseSensitive ? h : h.toLowerCase()))
+ const { exclude: excludeSet } = headerFilters
for (const [key, value] of Object.entries(headers)) {
const headerKey = caseSensitive ? key : key.toLowerCase()
@@ -86,106 +172,81 @@ function filterHeadersForStorage (headers, matchOptions = {}) {
}
/**
- * Creates cached header sets for performance
+ * Creates a hash key for request matching
+ * Properly orders headers to avoid conflicts and uses crypto hashing when available
+ *
+ * @param {SnapshotFormattedRequest} formattedRequest - Request object
+ * @returns {string} - Base64url encoded hash of the request
*/
-function createHeaderSetsCache (matchOptions = {}) {
- const { ignoreHeaders = [], excludeHeaders = [], matchHeaders = null, caseSensitive = false } = matchOptions
+function createRequestHash (formattedRequest) {
+ const parts = [
+ formattedRequest.method,
+ formattedRequest.url
+ ]
- return {
- ignoreSet: new Set(ignoreHeaders.map(h => caseSensitive ? h : h.toLowerCase())),
- excludeSet: new Set(excludeHeaders.map(h => caseSensitive ? h : h.toLowerCase())),
- matchSet: matchHeaders && Array.isArray(matchHeaders)
- ? new Set(matchHeaders.map(h => caseSensitive ? h : h.toLowerCase()))
- : null
- }
-}
+ // Process headers in a deterministic way to avoid conflicts
+ if (formattedRequest.headers && typeof formattedRequest.headers === 'object') {
+ const headerKeys = Object.keys(formattedRequest.headers).sort()
+ for (const key of headerKeys) {
+ const values = Array.isArray(formattedRequest.headers[key])
+ ? formattedRequest.headers[key]
+ : [formattedRequest.headers[key]]
-/**
- * Normalizes headers for consistent comparison
- */
-function normalizeHeaders (headers) {
- if (!headers) return {}
-
- const normalized = {}
-
- // Handle array format (undici internal format: [name, value, name, value, ...])
- if (Array.isArray(headers)) {
- for (let i = 0; i < headers.length; i += 2) {
- const key = headers[i]
- const value = headers[i + 1]
- if (key && value !== undefined) {
- // Convert Buffers to strings if needed
- const keyStr = Buffer.isBuffer(key) ? key.toString() : String(key)
- const valueStr = Buffer.isBuffer(value) ? value.toString() : String(value)
- normalized[keyStr.toLowerCase()] = valueStr
- }
- }
- return normalized
- }
+ // Add header name
+ parts.push(key)
- // Handle object format
- if (headers && typeof headers === 'object') {
- for (const [key, value] of Object.entries(headers)) {
- if (key && typeof key === 'string') {
- normalized[key.toLowerCase()] = Array.isArray(value) ? value.join(', ') : String(value)
+ // Add all values for this header, sorted for consistency
+ for (const value of values.sort()) {
+ parts.push(String(value))
}
}
}
- return normalized
-}
+ // Add body
+ parts.push(formattedRequest.body)
-/**
- * Creates a hash key for request matching
- */
-function createRequestHash (request) {
- const parts = [
- request.method,
- request.url,
- JSON.stringify(request.headers, Object.keys(request.headers).sort()),
- request.body || ''
- ]
- return Buffer.from(parts.join('|')).toString('base64url')
-}
+ const content = parts.join('|')
-/**
- * Checks if a URL matches any of the exclude patterns
- */
-function isUrlExcluded (url, excludePatterns = []) {
- if (!excludePatterns.length) return false
-
- for (const pattern of excludePatterns) {
- if (typeof pattern === 'string') {
- // Simple string match (case-insensitive)
- if (url.toLowerCase().includes(pattern.toLowerCase())) {
- return true
- }
- } else if (pattern instanceof RegExp) {
- // Regex pattern match
- if (pattern.test(url)) {
- return true
- }
- }
- }
-
- return false
+ return hashId(content)
}
class SnapshotRecorder {
+ /** @type {NodeJS.Timeout | null} */
+ #flushTimeout
+
+ /** @type {import('./snapshot-utils').IsUrlExcluded} */
+ #isUrlExcluded
+
+ /** @type {Map} */
+ #snapshots = new Map()
+
+ /** @type {string|undefined} */
+ #snapshotPath
+
+ /** @type {number} */
+ #maxSnapshots = Infinity
+
+ /** @type {boolean} */
+ #autoFlush = false
+
+ /** @type {import('./snapshot-utils').HeaderFilters} */
+ #headerFilters
+
+ /**
+ * Creates a new SnapshotRecorder instance
+ * @param {SnapshotRecorderOptions&SnapshotRecorderMatchOptions} [options={}] - Configuration options for the recorder
+ */
constructor (options = {}) {
- this.snapshots = new Map()
- this.snapshotPath = options.snapshotPath
- this.mode = options.mode || 'record'
- this.loaded = false
- this.maxSnapshots = options.maxSnapshots || Infinity
- this.autoFlush = options.autoFlush || false
+ this.#snapshotPath = options.snapshotPath
+ this.#maxSnapshots = options.maxSnapshots || Infinity
+ this.#autoFlush = options.autoFlush || false
this.flushInterval = options.flushInterval || 30000 // 30 seconds default
this._flushTimer = null
- this._flushTimeout = null
// Matching configuration
+ /** @type {Required} */
this.matchOptions = {
- matchHeaders: options.matchHeaders || null, // null means match all headers
+ matchHeaders: options.matchHeaders || [], // empty means match all headers
ignoreHeaders: options.ignoreHeaders || [],
excludeHeaders: options.excludeHeaders || [],
matchBody: options.matchBody !== false, // default: true
@@ -194,46 +255,49 @@ class SnapshotRecorder {
}
// Cache processed header sets to avoid recreating them on every request
- this._headerSetsCache = createHeaderSetsCache(this.matchOptions)
+ this.#headerFilters = createHeaderFilters(this.matchOptions)
// Request filtering callbacks
- this.shouldRecord = options.shouldRecord || null // function(requestOpts) -> boolean
- this.shouldPlayback = options.shouldPlayback || null // function(requestOpts) -> boolean
+ this.shouldRecord = options.shouldRecord || (() => true) // function(requestOpts) -> boolean
+ this.shouldPlayback = options.shouldPlayback || (() => true) // function(requestOpts) -> boolean
// URL pattern filtering
- this.excludeUrls = options.excludeUrls || [] // Array of regex patterns or strings
+ this.#isUrlExcluded = isUrlExcludedFactory(options.excludeUrls) // Array of regex patterns or strings
// Start auto-flush timer if enabled
- if (this.autoFlush && this.snapshotPath) {
- this._startAutoFlush()
+ if (this.#autoFlush && this.#snapshotPath) {
+ this.#startAutoFlush()
}
}
/**
* Records a request-response interaction
+ * @param {SnapshotRequestOptions} requestOpts - Request options
+ * @param {SnapshotEntryResponse} response - Response data to record
+ * @return {Promise} - Resolves when the recording is complete
*/
async record (requestOpts, response) {
// Check if recording should be filtered out
- if (this.shouldRecord && typeof this.shouldRecord === 'function') {
- if (!this.shouldRecord(requestOpts)) {
- return // Skip recording
- }
+ if (!this.shouldRecord(requestOpts)) {
+ return // Skip recording
}
// Check URL exclusion patterns
const url = new URL(requestOpts.path, requestOpts.origin).toString()
- if (isUrlExcluded(url, this.excludeUrls)) {
+ if (this.#isUrlExcluded(url)) {
return // Skip recording
}
- const request = formatRequestKey(requestOpts, this._headerSetsCache, this.matchOptions)
+ const request = formatRequestKey(requestOpts, this.#headerFilters, this.matchOptions)
const hash = createRequestHash(request)
// Extract response data - always store body as base64
const normalizedHeaders = normalizeHeaders(response.headers)
+
+ /** @type {SnapshotEntryResponse} */
const responseData = {
statusCode: response.statusCode,
- headers: filterHeadersForStorage(normalizedHeaders, this.matchOptions),
+ headers: filterHeadersForStorage(normalizedHeaders, this.#headerFilters, this.matchOptions),
body: Buffer.isBuffer(response.body)
? response.body.toString('base64')
: Buffer.from(String(response.body || '')).toString('base64'),
@@ -241,18 +305,18 @@ class SnapshotRecorder {
}
// Remove oldest snapshot if we exceed maxSnapshots limit
- if (this.snapshots.size >= this.maxSnapshots && !this.snapshots.has(hash)) {
- const oldestKey = this.snapshots.keys().next().value
- this.snapshots.delete(oldestKey)
+ if (this.#snapshots.size >= this.#maxSnapshots && !this.#snapshots.has(hash)) {
+ const oldestKey = this.#snapshots.keys().next().value
+ this.#snapshots.delete(oldestKey)
}
// Support sequential responses - if snapshot exists, add to responses array
- const existingSnapshot = this.snapshots.get(hash)
+ const existingSnapshot = this.#snapshots.get(hash)
if (existingSnapshot && existingSnapshot.responses) {
existingSnapshot.responses.push(responseData)
existingSnapshot.timestamp = new Date().toISOString()
} else {
- this.snapshots.set(hash, {
+ this.#snapshots.set(hash, {
request,
responses: [responseData], // Always store as array for consistency
callCount: 0,
@@ -261,67 +325,54 @@ class SnapshotRecorder {
}
// Auto-flush if enabled
- if (this.autoFlush && this.snapshotPath) {
- this._scheduleFlush()
+ if (this.#autoFlush && this.#snapshotPath) {
+ this.#scheduleFlush()
}
}
/**
* Finds a matching snapshot for the given request
* Returns the appropriate response based on call count for sequential responses
+ *
+ * @param {SnapshotRequestOptions} requestOpts - Request options to match
+ * @returns {SnapshotEntry&Record<'response', SnapshotEntryResponse>|undefined} - Matching snapshot response or undefined if not found
*/
findSnapshot (requestOpts) {
// Check if playback should be filtered out
- if (this.shouldPlayback && typeof this.shouldPlayback === 'function') {
- if (!this.shouldPlayback(requestOpts)) {
- return undefined // Skip playback
- }
+ if (!this.shouldPlayback(requestOpts)) {
+ return undefined // Skip playback
}
// Check URL exclusion patterns
const url = new URL(requestOpts.path, requestOpts.origin).toString()
- if (isUrlExcluded(url, this.excludeUrls)) {
+ if (this.#isUrlExcluded(url)) {
return undefined // Skip playback
}
- const request = formatRequestKey(requestOpts, this._headerSetsCache, this.matchOptions)
+ const request = formatRequestKey(requestOpts, this.#headerFilters, this.matchOptions)
const hash = createRequestHash(request)
- const snapshot = this.snapshots.get(hash)
+ const snapshot = this.#snapshots.get(hash)
if (!snapshot) return undefined
// Handle sequential responses
- if (snapshot.responses && Array.isArray(snapshot.responses)) {
- const currentCallCount = snapshot.callCount || 0
- const responseIndex = Math.min(currentCallCount, snapshot.responses.length - 1)
- snapshot.callCount = currentCallCount + 1
-
- return {
- ...snapshot,
- response: snapshot.responses[responseIndex]
- }
- }
+ const currentCallCount = snapshot.callCount || 0
+ const responseIndex = Math.min(currentCallCount, snapshot.responses.length - 1)
+ snapshot.callCount = currentCallCount + 1
- // Legacy format compatibility - convert single response to array format
- if (snapshot.response && !snapshot.responses) {
- snapshot.responses = [snapshot.response]
- snapshot.callCount = 1
- delete snapshot.response
-
- return {
- ...snapshot,
- response: snapshot.responses[0]
- }
+ return {
+ ...snapshot,
+ response: snapshot.responses[responseIndex]
}
-
- return snapshot
}
/**
* Loads snapshots from file
+ * @param {string} [filePath] - Optional file path to load snapshots from
+ * @return {Promise} - Resolves when snapshots are loaded
*/
async loadSnapshots (filePath) {
- const path = filePath || this.snapshotPath
+ const path = filePath || this.#snapshotPath
if (!path) {
throw new InvalidArgumentError('Snapshot path is required')
}
@@ -332,21 +383,18 @@ class SnapshotRecorder {
// Convert array format back to Map
if (Array.isArray(parsed)) {
- this.snapshots.clear()
+ this.#snapshots.clear()
for (const { hash, snapshot } of parsed) {
- this.snapshots.set(hash, snapshot)
+ this.#snapshots.set(hash, snapshot)
}
} else {
// Legacy object format
- this.snapshots = new Map(Object.entries(parsed))
+ this.#snapshots = new Map(Object.entries(parsed))
}
-
- this.loaded = true
} catch (error) {
if (error.code === 'ENOENT') {
// File doesn't exist yet - that's ok for recording mode
- this.snapshots.clear()
- this.loaded = true
+ this.#snapshots.clear()
} else {
throw new UndiciError(`Failed to load snapshots from ${path}`, { cause: error })
}
@@ -355,9 +403,12 @@ class SnapshotRecorder {
/**
* Saves snapshots to file
+ *
+ * @param {string} [filePath] - Optional file path to save snapshots
+ * @returns {Promise} - Resolves when snapshots are saved
*/
async saveSnapshots (filePath) {
- const path = filePath || this.snapshotPath
+ const path = filePath || this.#snapshotPath
if (!path) {
throw new InvalidArgumentError('Snapshot path is required')
}
@@ -368,67 +419,75 @@ class SnapshotRecorder {
await mkdir(dirname(resolvedPath), { recursive: true })
// Convert Map to serializable format
- const data = Array.from(this.snapshots.entries()).map(([hash, snapshot]) => ({
+ const data = Array.from(this.#snapshots.entries()).map(([hash, snapshot]) => ({
hash,
snapshot
}))
- await writeFile(resolvedPath, JSON.stringify(data, null, 2), 'utf8', { flush: true })
+ await writeFile(resolvedPath, JSON.stringify(data, null, 2), { flush: true })
}
/**
* Clears all recorded snapshots
+ * @returns {void}
*/
clear () {
- this.snapshots.clear()
+ this.#snapshots.clear()
}
/**
* Gets all recorded snapshots
+ * @return {Array} - Array of all recorded snapshots
*/
getSnapshots () {
- return Array.from(this.snapshots.values())
+ return Array.from(this.#snapshots.values())
}
/**
* Gets snapshot count
+ * @return {number} - Number of recorded snapshots
*/
size () {
- return this.snapshots.size
+ return this.#snapshots.size
}
/**
* Resets call counts for all snapshots (useful for test cleanup)
+ * @returns {void}
*/
resetCallCounts () {
- for (const snapshot of this.snapshots.values()) {
+ for (const snapshot of this.#snapshots.values()) {
snapshot.callCount = 0
}
}
/**
* Deletes a specific snapshot by request options
+ * @param {SnapshotRequestOptions} requestOpts - Request options to match
+ * @returns {boolean} - True if snapshot was deleted, false if not found
*/
deleteSnapshot (requestOpts) {
- const request = formatRequestKey(requestOpts, this._headerSetsCache, this.matchOptions)
+ const request = formatRequestKey(requestOpts, this.#headerFilters, this.matchOptions)
const hash = createRequestHash(request)
- return this.snapshots.delete(hash)
+ return this.#snapshots.delete(hash)
}
/**
* Gets information about a specific snapshot
+ * @param {SnapshotRequestOptions} requestOpts - Request options to match
+ * @returns {SnapshotInfo|null} - Snapshot information or null if not found
*/
getSnapshotInfo (requestOpts) {
- const request = formatRequestKey(requestOpts, this._headerSetsCache, this.matchOptions)
+ const request = formatRequestKey(requestOpts, this.#headerFilters, this.matchOptions)
const hash = createRequestHash(request)
- const snapshot = this.snapshots.get(hash)
+ const snapshot = this.#snapshots.get(hash)
if (!snapshot) return null
return {
hash,
request: snapshot.request,
- responseCount: snapshot.responses ? snapshot.responses.length : (snapshot.response ? 1 : 0),
+ responseCount: snapshot.responses ? snapshot.responses.length : (snapshot.response ? 1 : 0), // .response for legacy snapshots
callCount: snapshot.callCount || 0,
timestamp: snapshot.timestamp
}
@@ -436,76 +495,80 @@ class SnapshotRecorder {
/**
* Replaces all snapshots with new data (full replacement)
+ * @param {Array<{hash: string; snapshot: SnapshotEntry}>|Record} snapshotData - New snapshot data to replace existing ones
+ * @returns {void}
*/
replaceSnapshots (snapshotData) {
- this.snapshots.clear()
+ this.#snapshots.clear()
if (Array.isArray(snapshotData)) {
for (const { hash, snapshot } of snapshotData) {
- this.snapshots.set(hash, snapshot)
+ this.#snapshots.set(hash, snapshot)
}
} else if (snapshotData && typeof snapshotData === 'object') {
// Legacy object format
- this.snapshots = new Map(Object.entries(snapshotData))
+ this.#snapshots = new Map(Object.entries(snapshotData))
}
}
/**
* Starts the auto-flush timer
+ * @returns {void}
*/
- _startAutoFlush () {
- if (!this._flushTimer) {
- this._flushTimer = setInterval(() => {
- this.saveSnapshots().catch(() => {
- // Ignore flush errors - they shouldn't interrupt normal operation
- })
- }, this.flushInterval)
- }
+ #startAutoFlush () {
+ return this.#scheduleFlush()
}
/**
* Stops the auto-flush timer
+ * @returns {void}
*/
- _stopAutoFlush () {
- if (this._flushTimer) {
- clearInterval(this._flushTimer)
- this._flushTimer = null
+ #stopAutoFlush () {
+ if (this.#flushTimeout) {
+ clearTimeout(this.#flushTimeout)
+ // Ensure any pending flush is completed
+ this.saveSnapshots().catch(() => {
+ // Ignore flush errors
+ })
+ this.#flushTimeout = null
}
}
/**
* Schedules a flush (debounced to avoid excessive writes)
*/
- _scheduleFlush () {
- // Simple debouncing - clear existing timeout and set new one
- if (this._flushTimeout) {
- clearTimeout(this._flushTimeout)
- }
- this._flushTimeout = setTimeout(() => {
+ #scheduleFlush () {
+ this.#flushTimeout = setTimeout(() => {
this.saveSnapshots().catch(() => {
// Ignore flush errors
})
- this._flushTimeout = null
+ if (this.#autoFlush) {
+ this.#flushTimeout?.refresh()
+ } else {
+ this.#flushTimeout = null
+ }
}, 1000) // 1 second debounce
}
/**
* Cleanup method to stop timers
+ * @returns {void}
*/
destroy () {
- this._stopAutoFlush()
- if (this._flushTimeout) {
- clearTimeout(this._flushTimeout)
- this._flushTimeout = null
+ this.#stopAutoFlush()
+ if (this.#flushTimeout) {
+ clearTimeout(this.#flushTimeout)
+ this.#flushTimeout = null
}
}
/**
* Async close method that saves all recordings and performs cleanup
+ * @returns {Promise}
*/
async close () {
// Save any pending recordings if we have a snapshot path
- if (this.snapshotPath && this.snapshots.size > 0) {
+ if (this.#snapshotPath && this.#snapshots.size !== 0) {
await this.saveSnapshots()
}
@@ -514,4 +577,4 @@ class SnapshotRecorder {
}
}
-module.exports = { SnapshotRecorder, formatRequestKey, createRequestHash, filterHeadersForMatching, filterHeadersForStorage, isUrlExcluded, createHeaderSetsCache }
+module.exports = { SnapshotRecorder, formatRequestKey, createRequestHash, filterHeadersForMatching, filterHeadersForStorage, createHeaderFilters }
diff --git a/deps/undici/src/lib/mock/snapshot-utils.js b/deps/undici/src/lib/mock/snapshot-utils.js
new file mode 100644
index 00000000000000..ebad12e888ff29
--- /dev/null
+++ b/deps/undici/src/lib/mock/snapshot-utils.js
@@ -0,0 +1,158 @@
+'use strict'
+
+const { InvalidArgumentError } = require('../core/errors')
+
+/**
+ * @typedef {Object} HeaderFilters
+ * @property {Set} ignore - Set of headers to ignore for matching
+ * @property {Set} exclude - Set of headers to exclude from matching
+ * @property {Set} match - Set of headers to match (empty means match
+ */
+
+/**
+ * Creates cached header sets for performance
+ *
+ * @param {import('./snapshot-recorder').SnapshotRecorderMatchOptions} matchOptions - Matching options for headers
+ * @returns {HeaderFilters} - Cached sets for ignore, exclude, and match headers
+ */
+function createHeaderFilters (matchOptions = {}) {
+ const { ignoreHeaders = [], excludeHeaders = [], matchHeaders = [], caseSensitive = false } = matchOptions
+
+ return {
+ ignore: new Set(ignoreHeaders.map(header => caseSensitive ? header : header.toLowerCase())),
+ exclude: new Set(excludeHeaders.map(header => caseSensitive ? header : header.toLowerCase())),
+ match: new Set(matchHeaders.map(header => caseSensitive ? header : header.toLowerCase()))
+ }
+}
+
+let crypto
+try {
+ crypto = require('node:crypto')
+} catch { /* Fallback if crypto is not available */ }
+
+/**
+ * @callback HashIdFunction
+ * @param {string} value - The value to hash
+ * @returns {string} - The base64url encoded hash of the value
+ */
+
+/**
+ * Generates a hash for a given value
+ * @type {HashIdFunction}
+ */
+const hashId = crypto?.hash
+ ? (value) => crypto.hash('sha256', value, 'base64url')
+ : (value) => Buffer.from(value).toString('base64url')
+
+/**
+ * @typedef {(url: string) => boolean} IsUrlExcluded Checks if a URL matches any of the exclude patterns
+ */
+
+/** @typedef {{[key: Lowercase]: string}} NormalizedHeaders */
+/** @typedef {Array} UndiciHeaders */
+/** @typedef {Record} Headers */
+
+/**
+ * @param {*} headers
+ * @returns {headers is UndiciHeaders}
+ */
+function isUndiciHeaders (headers) {
+ return Array.isArray(headers) && (headers.length & 1) === 0
+}
+
+/**
+ * Factory function to create a URL exclusion checker
+ * @param {Array} [excludePatterns=[]] - Array of patterns to exclude
+ * @returns {IsUrlExcluded} - A function that checks if a URL matches any of the exclude patterns
+ */
+function isUrlExcludedFactory (excludePatterns = []) {
+ if (excludePatterns.length === 0) {
+ return () => false
+ }
+
+ return function isUrlExcluded (url) {
+ let urlLowerCased
+
+ for (const pattern of excludePatterns) {
+ if (typeof pattern === 'string') {
+ if (!urlLowerCased) {
+ // Convert URL to lowercase only once
+ urlLowerCased = url.toLowerCase()
+ }
+ // Simple string match (case-insensitive)
+ if (urlLowerCased.includes(pattern.toLowerCase())) {
+ return true
+ }
+ } else if (pattern instanceof RegExp) {
+ // Regex pattern match
+ if (pattern.test(url)) {
+ return true
+ }
+ }
+ }
+
+ return false
+ }
+}
+
+/**
+ * Normalizes headers for consistent comparison
+ *
+ * @param {Object|UndiciHeaders} headers - Headers to normalize
+ * @returns {NormalizedHeaders} - Normalized headers as a lowercase object
+ */
+function normalizeHeaders (headers) {
+ /** @type {NormalizedHeaders} */
+ const normalizedHeaders = {}
+
+ if (!headers) return normalizedHeaders
+
+ // Handle array format (undici internal format: [name, value, name, value, ...])
+ if (isUndiciHeaders(headers)) {
+ for (let i = 0; i < headers.length; i += 2) {
+ const key = headers[i]
+ const value = headers[i + 1]
+ if (key && value !== undefined) {
+ // Convert Buffers to strings if needed
+ const keyStr = Buffer.isBuffer(key) ? key.toString() : key
+ const valueStr = Buffer.isBuffer(value) ? value.toString() : value
+ normalizedHeaders[keyStr.toLowerCase()] = valueStr
+ }
+ }
+ return normalizedHeaders
+ }
+
+ // Handle object format
+ if (headers && typeof headers === 'object') {
+ for (const [key, value] of Object.entries(headers)) {
+ if (key && typeof key === 'string') {
+ normalizedHeaders[key.toLowerCase()] = Array.isArray(value) ? value.join(', ') : String(value)
+ }
+ }
+ }
+
+ return normalizedHeaders
+}
+
+const validSnapshotModes = /** @type {const} */ (['record', 'playback', 'update'])
+
+/** @typedef {typeof validSnapshotModes[number]} SnapshotMode */
+
+/**
+ * @param {*} mode - The snapshot mode to validate
+ * @returns {asserts mode is SnapshotMode}
+ */
+function validateSnapshotMode (mode) {
+ if (!validSnapshotModes.includes(mode)) {
+ throw new InvalidArgumentError(`Invalid snapshot mode: ${mode}. Must be one of: ${validSnapshotModes.join(', ')}`)
+ }
+}
+
+module.exports = {
+ createHeaderFilters,
+ hashId,
+ isUndiciHeaders,
+ normalizeHeaders,
+ isUrlExcludedFactory,
+ validateSnapshotMode
+}
diff --git a/deps/undici/src/lib/util/cache.js b/deps/undici/src/lib/util/cache.js
index 53851df1d1bbd9..3c2eb0dbd29d6a 100644
--- a/deps/undici/src/lib/util/cache.js
+++ b/deps/undici/src/lib/util/cache.js
@@ -34,7 +34,7 @@ function makeCacheKey (opts) {
* @param {Record}
* @returns {Record}
*/
-function normaliseHeaders (opts) {
+function normalizeHeaders (opts) {
let headers
if (opts.headers == null) {
headers = {}
@@ -234,7 +234,7 @@ function parseCacheControlHeader (header) {
}
}
} else {
- // Something like `no-cache=some-header`
+ // Something like `no-cache="some-header"`
if (key in output) {
output[key] = output[key].concat(value)
} else {
@@ -367,7 +367,7 @@ function assertCacheMethods (methods, name = 'CacheMethods') {
module.exports = {
makeCacheKey,
- normaliseHeaders,
+ normalizeHeaders,
assertCacheKey,
assertCacheValue,
parseCacheControlHeader,
diff --git a/deps/undici/src/lib/web/cache/cache.js b/deps/undici/src/lib/web/cache/cache.js
index dd9e2f8163ad3a..70a3787a71d415 100644
--- a/deps/undici/src/lib/web/cache/cache.js
+++ b/deps/undici/src/lib/web/cache/cache.js
@@ -18,7 +18,7 @@ const { createDeferredPromise } = require('../../util/promise')
* @property {'delete' | 'put'} type
* @property {any} request
* @property {any} response
- * @property {import('../../types/cache').CacheQueryOptions} options
+ * @property {import('../../../types/cache').CacheQueryOptions} options
*/
/**
@@ -452,7 +452,7 @@ class Cache {
/**
* @see https://w3c.github.io/ServiceWorker/#dom-cache-keys
* @param {any} request
- * @param {import('../../types/cache').CacheQueryOptions} options
+ * @param {import('../../../types/cache').CacheQueryOptions} options
* @returns {Promise}
*/
async keys (request = undefined, options = {}) {
@@ -670,7 +670,7 @@ class Cache {
/**
* @see https://w3c.github.io/ServiceWorker/#query-cache
* @param {any} requestQuery
- * @param {import('../../types/cache').CacheQueryOptions} options
+ * @param {import('../../../types/cache').CacheQueryOptions} options
* @param {requestResponseList} targetStorage
* @returns {requestResponseList}
*/
@@ -695,7 +695,7 @@ class Cache {
* @param {any} requestQuery
* @param {any} request
* @param {any | null} response
- * @param {import('../../types/cache').CacheQueryOptions | undefined} options
+ * @param {import('../../../types/cache').CacheQueryOptions | undefined} options
* @returns {boolean}
*/
#requestMatchesCachedItem (requestQuery, request, response = null, options) {
diff --git a/deps/undici/src/lib/web/eventsource/eventsource.js b/deps/undici/src/lib/web/eventsource/eventsource.js
index 746400b8ea97a5..1ff4e36ca2a071 100644
--- a/deps/undici/src/lib/web/eventsource/eventsource.js
+++ b/deps/undici/src/lib/web/eventsource/eventsource.js
@@ -124,10 +124,10 @@ class EventSource extends EventTarget {
url = webidl.converters.USVString(url)
eventSourceInitDict = webidl.converters.EventSourceInitDict(eventSourceInitDict, prefix, 'eventSourceInitDict')
- this.#dispatcher = eventSourceInitDict.dispatcher
+ this.#dispatcher = eventSourceInitDict.node.dispatcher || eventSourceInitDict.dispatcher
this.#state = {
lastEventId: '',
- reconnectionTime: defaultReconnectionTime
+ reconnectionTime: eventSourceInitDict.node.reconnectionTime
}
// 2. Let settings be ev's relevant settings object.
@@ -472,6 +472,21 @@ webidl.converters.EventSourceInitDict = webidl.dictionaryConverter([
{
key: 'dispatcher', // undici only
converter: webidl.converters.any
+ },
+ {
+ key: 'node', // undici only
+ converter: webidl.dictionaryConverter([
+ {
+ key: 'reconnectionTime',
+ converter: webidl.converters['unsigned long'],
+ defaultValue: () => defaultReconnectionTime
+ },
+ {
+ key: 'dispatcher',
+ converter: webidl.converters.any
+ }
+ ]),
+ defaultValue: () => ({})
}
])
diff --git a/deps/undici/src/lib/web/fetch/formdata.js b/deps/undici/src/lib/web/fetch/formdata.js
index e21ee3f553e96e..c21fb06a3eeb62 100644
--- a/deps/undici/src/lib/web/fetch/formdata.js
+++ b/deps/undici/src/lib/web/fetch/formdata.js
@@ -9,7 +9,7 @@ const nodeUtil = require('node:util')
class FormData {
#state = []
- constructor (form) {
+ constructor (form = undefined) {
webidl.util.markAsUncloneable(this)
if (form !== undefined) {
diff --git a/deps/undici/src/lib/web/fetch/response.js b/deps/undici/src/lib/web/fetch/response.js
index fba44ef6dcacf0..5f11f449477f8b 100644
--- a/deps/undici/src/lib/web/fetch/response.js
+++ b/deps/undici/src/lib/web/fetch/response.js
@@ -22,7 +22,8 @@ const { webidl } = require('../webidl')
const { URLSerializer } = require('./data-url')
const { kConstruct } = require('../../core/symbols')
const assert = require('node:assert')
-const { types } = require('node:util')
+
+const { isArrayBuffer } = nodeUtil.types
const textEncoder = new TextEncoder('utf-8')
@@ -243,6 +244,11 @@ class Response {
// 2. Let clonedResponse be the result of cloning this’s response.
const clonedResponse = cloneResponse(this.#state)
+ // Note: To re-register because of a new stream.
+ if (this.#state.body?.stream) {
+ streamRegistry.register(this, new WeakRef(this.#state.body.stream))
+ }
+
// 3. Return the result of creating a Response object, given
// clonedResponse, this’s headers’s guard, and this’s relevant Realm.
return fromInnerResponse(clonedResponse, getHeadersGuard(this.#headers))
@@ -353,8 +359,6 @@ function cloneResponse (response) {
// result of cloning response’s body.
if (response.body != null) {
newResponse.body = cloneBody(response.body)
-
- streamRegistry.register(newResponse, new WeakRef(response.body.stream))
}
// 4. Return newResponse.
@@ -576,7 +580,7 @@ webidl.converters.XMLHttpRequestBodyInit = function (V, prefix, name) {
return V
}
- if (ArrayBuffer.isView(V) || types.isArrayBuffer(V)) {
+ if (ArrayBuffer.isView(V) || isArrayBuffer(V)) {
return V
}
diff --git a/deps/undici/src/lib/web/websocket/stream/websocketstream.js b/deps/undici/src/lib/web/websocket/stream/websocketstream.js
index dc364a00e66160..e7a8bce614a11d 100644
--- a/deps/undici/src/lib/web/websocket/stream/websocketstream.js
+++ b/deps/undici/src/lib/web/websocket/stream/websocketstream.js
@@ -6,7 +6,7 @@ const { states, opcodes, sentCloseFrameState } = require('../constants')
const { webidl } = require('../../webidl')
const { getURLRecord, isValidSubprotocol, isEstablished, utf8Decode } = require('../util')
const { establishWebSocketConnection, failWebsocketConnection, closeWebSocketConnection } = require('../connection')
-const { types } = require('node:util')
+const { isArrayBuffer } = require('node:util/types')
const { channels } = require('../../../core/diagnostics')
const { WebsocketFrameSend } = require('../frame')
const { ByteParser } = require('../receiver')
@@ -210,7 +210,7 @@ class WebSocketStream {
let opcode = null
// 4. If chunk is a BufferSource ,
- if (ArrayBuffer.isView(chunk) || types.isArrayBuffer(chunk)) {
+ if (ArrayBuffer.isView(chunk) || isArrayBuffer(chunk)) {
// 4.1. Set data to a copy of the bytes given chunk .
data = new Uint8Array(ArrayBuffer.isView(chunk) ? new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength) : chunk)
diff --git a/deps/undici/src/lib/web/websocket/websocket.js b/deps/undici/src/lib/web/websocket/websocket.js
index 5688c8ad8a0563..1f10cb0a73a7ed 100644
--- a/deps/undici/src/lib/web/websocket/websocket.js
+++ b/deps/undici/src/lib/web/websocket/websocket.js
@@ -1,5 +1,6 @@
'use strict'
+const { isArrayBuffer } = require('node:util/types')
const { webidl } = require('../webidl')
const { URLSerializer } = require('../fetch/data-url')
const { environmentSettingsObject } = require('../fetch/util')
@@ -19,7 +20,6 @@ const { establishWebSocketConnection, closeWebSocketConnection, failWebsocketCon
const { ByteParser } = require('./receiver')
const { kEnumerableProperty } = require('../../core/util')
const { getGlobalDispatcher } = require('../../global')
-const { types } = require('node:util')
const { ErrorEvent, CloseEvent, createFastMessageEvent } = require('./events')
const { SendQueue } = require('./sender')
const { WebsocketFrameSend } = require('./frame')
@@ -257,7 +257,7 @@ class WebSocket extends EventTarget {
this.#sendQueue.add(buffer, () => {
this.#bufferedAmount -= buffer.byteLength
}, sendHints.text)
- } else if (types.isArrayBuffer(data)) {
+ } else if (isArrayBuffer(data)) {
// If the WebSocket connection is established, and the WebSocket
// closing handshake has not yet started, then the user agent must
// send a WebSocket Message comprised of data using a binary frame
@@ -482,11 +482,18 @@ class WebSocket extends EventTarget {
fireEvent('open', this)
if (channels.open.hasSubscribers) {
+ // Convert headers to a plain object for the event
+ const headers = response.headersList.entries
channels.open.publish({
address: response.socket.address(),
protocol: this.#protocol,
extensions: this.#extensions,
- websocket: this
+ websocket: this,
+ handshakeResponse: {
+ status: response.status,
+ statusText: response.statusText,
+ headers
+ }
})
}
}
@@ -728,7 +735,7 @@ webidl.converters.WebSocketSendData = function (V) {
return V
}
- if (ArrayBuffer.isView(V) || types.isArrayBuffer(V)) {
+ if (ArrayBuffer.isView(V) || isArrayBuffer(V)) {
return V
}
}
diff --git a/deps/undici/src/package-lock.json b/deps/undici/src/package-lock.json
index 57498279f5040c..80ef7918ad3918 100644
--- a/deps/undici/src/package-lock.json
+++ b/deps/undici/src/package-lock.json
@@ -1,33 +1,33 @@
{
"name": "undici",
- "version": "7.13.0",
+ "version": "7.14.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "undici",
- "version": "7.13.0",
+ "version": "7.14.0",
"license": "MIT",
"devDependencies": {
"@fastify/busboy": "3.1.1",
"@matteo.collina/tspl": "^0.2.0",
+ "@metcoder95/https-pem": "^1.0.0",
"@sinonjs/fake-timers": "^12.0.0",
"@types/node": "^18.19.50",
"abort-controller": "^3.0.0",
"borp": "^0.20.0",
"c8": "^10.0.0",
- "cross-env": "^7.0.3",
+ "cross-env": "^10.0.0",
"dns-packet": "^5.4.0",
"esbuild": "^0.25.2",
"eslint": "^9.9.0",
"fast-check": "^4.1.1",
- "https-pem": "^3.0.0",
"husky": "^9.0.7",
- "jest": "^29.0.2",
+ "jest": "^30.0.5",
"neostandard": "^0.12.0",
"node-forge": "^1.3.1",
"proxy": "^2.1.1",
- "tsd": "^0.32.0",
+ "tsd": "^0.33.0",
"typescript": "^5.6.2",
"ws": "^8.11.0"
},
@@ -114,22 +114,22 @@
}
},
"node_modules/@babel/core": {
- "version": "7.28.0",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz",
- "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==",
+ "version": "7.28.3",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz",
+ "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.27.1",
- "@babel/generator": "^7.28.0",
+ "@babel/generator": "^7.28.3",
"@babel/helper-compilation-targets": "^7.27.2",
- "@babel/helper-module-transforms": "^7.27.3",
- "@babel/helpers": "^7.27.6",
- "@babel/parser": "^7.28.0",
+ "@babel/helper-module-transforms": "^7.28.3",
+ "@babel/helpers": "^7.28.3",
+ "@babel/parser": "^7.28.3",
"@babel/template": "^7.27.2",
- "@babel/traverse": "^7.28.0",
- "@babel/types": "^7.28.0",
+ "@babel/traverse": "^7.28.3",
+ "@babel/types": "^7.28.2",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
@@ -145,14 +145,14 @@
}
},
"node_modules/@babel/generator": {
- "version": "7.28.0",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz",
- "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==",
+ "version": "7.28.3",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz",
+ "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/parser": "^7.28.0",
- "@babel/types": "^7.28.0",
+ "@babel/parser": "^7.28.3",
+ "@babel/types": "^7.28.2",
"@jridgewell/gen-mapping": "^0.3.12",
"@jridgewell/trace-mapping": "^0.3.28",
"jsesc": "^3.0.2"
@@ -203,15 +203,15 @@
}
},
"node_modules/@babel/helper-module-transforms": {
- "version": "7.27.3",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz",
- "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==",
+ "version": "7.28.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz",
+ "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.27.1",
"@babel/helper-validator-identifier": "^7.27.1",
- "@babel/traverse": "^7.27.3"
+ "@babel/traverse": "^7.28.3"
},
"engines": {
"node": ">=6.9.0"
@@ -261,9 +261,9 @@
}
},
"node_modules/@babel/helpers": {
- "version": "7.28.2",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.2.tgz",
- "integrity": "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==",
+ "version": "7.28.3",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.3.tgz",
+ "integrity": "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -275,13 +275,13 @@
}
},
"node_modules/@babel/parser": {
- "version": "7.28.0",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz",
- "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==",
+ "version": "7.28.3",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.3.tgz",
+ "integrity": "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/types": "^7.28.0"
+ "@babel/types": "^7.28.2"
},
"bin": {
"parser": "bin/babel-parser.js"
@@ -545,18 +545,18 @@
}
},
"node_modules/@babel/traverse": {
- "version": "7.28.0",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz",
- "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==",
+ "version": "7.28.3",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.3.tgz",
+ "integrity": "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
- "@babel/generator": "^7.28.0",
+ "@babel/generator": "^7.28.3",
"@babel/helper-globals": "^7.28.0",
- "@babel/parser": "^7.28.0",
+ "@babel/parser": "^7.28.3",
"@babel/template": "^7.27.2",
- "@babel/types": "^7.28.0",
+ "@babel/types": "^7.28.2",
"debug": "^4.3.1"
},
"engines": {
@@ -621,10 +621,17 @@
"tslib": "^2.4.0"
}
},
+ "node_modules/@epic-web/invariant": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@epic-web/invariant/-/invariant-1.0.0.tgz",
+ "integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@esbuild/aix-ppc64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz",
- "integrity": "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz",
+ "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==",
"cpu": [
"ppc64"
],
@@ -639,9 +646,9 @@
}
},
"node_modules/@esbuild/android-arm": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.8.tgz",
- "integrity": "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz",
+ "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==",
"cpu": [
"arm"
],
@@ -656,9 +663,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.8.tgz",
- "integrity": "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz",
+ "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==",
"cpu": [
"arm64"
],
@@ -673,9 +680,9 @@
}
},
"node_modules/@esbuild/android-x64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.8.tgz",
- "integrity": "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz",
+ "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==",
"cpu": [
"x64"
],
@@ -690,9 +697,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz",
- "integrity": "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz",
+ "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==",
"cpu": [
"arm64"
],
@@ -707,9 +714,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.8.tgz",
- "integrity": "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz",
+ "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==",
"cpu": [
"x64"
],
@@ -724,9 +731,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.8.tgz",
- "integrity": "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz",
+ "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==",
"cpu": [
"arm64"
],
@@ -741,9 +748,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.8.tgz",
- "integrity": "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz",
+ "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==",
"cpu": [
"x64"
],
@@ -758,9 +765,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.8.tgz",
- "integrity": "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz",
+ "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==",
"cpu": [
"arm"
],
@@ -775,9 +782,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.8.tgz",
- "integrity": "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz",
+ "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==",
"cpu": [
"arm64"
],
@@ -792,9 +799,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.8.tgz",
- "integrity": "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz",
+ "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==",
"cpu": [
"ia32"
],
@@ -809,9 +816,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.8.tgz",
- "integrity": "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz",
+ "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==",
"cpu": [
"loong64"
],
@@ -826,9 +833,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.8.tgz",
- "integrity": "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz",
+ "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==",
"cpu": [
"mips64el"
],
@@ -843,9 +850,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.8.tgz",
- "integrity": "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz",
+ "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==",
"cpu": [
"ppc64"
],
@@ -860,9 +867,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.8.tgz",
- "integrity": "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz",
+ "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==",
"cpu": [
"riscv64"
],
@@ -877,9 +884,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.8.tgz",
- "integrity": "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz",
+ "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==",
"cpu": [
"s390x"
],
@@ -894,9 +901,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz",
- "integrity": "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz",
+ "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==",
"cpu": [
"x64"
],
@@ -911,9 +918,9 @@
}
},
"node_modules/@esbuild/netbsd-arm64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.8.tgz",
- "integrity": "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz",
+ "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==",
"cpu": [
"arm64"
],
@@ -928,9 +935,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.8.tgz",
- "integrity": "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz",
+ "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==",
"cpu": [
"x64"
],
@@ -945,9 +952,9 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.8.tgz",
- "integrity": "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz",
+ "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==",
"cpu": [
"arm64"
],
@@ -962,9 +969,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.8.tgz",
- "integrity": "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz",
+ "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==",
"cpu": [
"x64"
],
@@ -979,9 +986,9 @@
}
},
"node_modules/@esbuild/openharmony-arm64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.8.tgz",
- "integrity": "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz",
+ "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==",
"cpu": [
"arm64"
],
@@ -996,9 +1003,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.8.tgz",
- "integrity": "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz",
+ "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==",
"cpu": [
"x64"
],
@@ -1013,9 +1020,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.8.tgz",
- "integrity": "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz",
+ "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==",
"cpu": [
"arm64"
],
@@ -1030,9 +1037,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.8.tgz",
- "integrity": "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz",
+ "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==",
"cpu": [
"ia32"
],
@@ -1047,9 +1054,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz",
- "integrity": "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz",
+ "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==",
"cpu": [
"x64"
],
@@ -1121,9 +1128,9 @@
}
},
"node_modules/@eslint/config-helpers": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz",
- "integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==",
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz",
+ "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==",
"dev": true,
"license": "Apache-2.0",
"engines": {
@@ -1131,9 +1138,9 @@
}
},
"node_modules/@eslint/core": {
- "version": "0.15.1",
- "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz",
- "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==",
+ "version": "0.15.2",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz",
+ "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -1168,9 +1175,9 @@
}
},
"node_modules/@eslint/js": {
- "version": "9.32.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.32.0.tgz",
- "integrity": "sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==",
+ "version": "9.33.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.33.0.tgz",
+ "integrity": "sha512-5K1/mKhWaMfreBGJTwval43JJmkip0RmM+3+IuqupeSKNC/Th2Kc7ucaq5ovTSra/OOKB9c58CGSz3QMVbWt0A==",
"dev": true,
"license": "MIT",
"engines": {
@@ -1191,13 +1198,13 @@
}
},
"node_modules/@eslint/plugin-kit": {
- "version": "0.3.4",
- "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.4.tgz",
- "integrity": "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==",
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz",
+ "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "@eslint/core": "^0.15.1",
+ "@eslint/core": "^0.15.2",
"levn": "^0.4.1"
},
"engines": {
@@ -1457,61 +1464,61 @@
}
},
"node_modules/@jest/console": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz",
- "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.0.5.tgz",
+ "integrity": "sha512-xY6b0XiL0Nav3ReresUarwl2oIz1gTnxGbGpho9/rbUWsLH0f1OD/VT84xs8c7VmH7MChnLb0pag6PhZhAdDiA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/types": "^29.6.3",
+ "@jest/types": "30.0.5",
"@types/node": "*",
- "chalk": "^4.0.0",
- "jest-message-util": "^29.7.0",
- "jest-util": "^29.7.0",
+ "chalk": "^4.1.2",
+ "jest-message-util": "30.0.5",
+ "jest-util": "30.0.5",
"slash": "^3.0.0"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/core": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz",
- "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.0.5.tgz",
+ "integrity": "sha512-fKD0OulvRsXF1hmaFgHhVJzczWzA1RXMMo9LTPuFXo9q/alDbME3JIyWYqovWsUBWSoBcsHaGPSLF9rz4l9Qeg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/console": "^29.7.0",
- "@jest/reporters": "^29.7.0",
- "@jest/test-result": "^29.7.0",
- "@jest/transform": "^29.7.0",
- "@jest/types": "^29.6.3",
+ "@jest/console": "30.0.5",
+ "@jest/pattern": "30.0.1",
+ "@jest/reporters": "30.0.5",
+ "@jest/test-result": "30.0.5",
+ "@jest/transform": "30.0.5",
+ "@jest/types": "30.0.5",
"@types/node": "*",
- "ansi-escapes": "^4.2.1",
- "chalk": "^4.0.0",
- "ci-info": "^3.2.0",
- "exit": "^0.1.2",
- "graceful-fs": "^4.2.9",
- "jest-changed-files": "^29.7.0",
- "jest-config": "^29.7.0",
- "jest-haste-map": "^29.7.0",
- "jest-message-util": "^29.7.0",
- "jest-regex-util": "^29.6.3",
- "jest-resolve": "^29.7.0",
- "jest-resolve-dependencies": "^29.7.0",
- "jest-runner": "^29.7.0",
- "jest-runtime": "^29.7.0",
- "jest-snapshot": "^29.7.0",
- "jest-util": "^29.7.0",
- "jest-validate": "^29.7.0",
- "jest-watcher": "^29.7.0",
- "micromatch": "^4.0.4",
- "pretty-format": "^29.7.0",
- "slash": "^3.0.0",
- "strip-ansi": "^6.0.0"
+ "ansi-escapes": "^4.3.2",
+ "chalk": "^4.1.2",
+ "ci-info": "^4.2.0",
+ "exit-x": "^0.2.2",
+ "graceful-fs": "^4.2.11",
+ "jest-changed-files": "30.0.5",
+ "jest-config": "30.0.5",
+ "jest-haste-map": "30.0.5",
+ "jest-message-util": "30.0.5",
+ "jest-regex-util": "30.0.1",
+ "jest-resolve": "30.0.5",
+ "jest-resolve-dependencies": "30.0.5",
+ "jest-runner": "30.0.5",
+ "jest-runtime": "30.0.5",
+ "jest-snapshot": "30.0.5",
+ "jest-util": "30.0.5",
+ "jest-validate": "30.0.5",
+ "jest-watcher": "30.0.5",
+ "micromatch": "^4.0.8",
+ "pretty-format": "30.0.5",
+ "slash": "^3.0.0"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
},
"peerDependencies": {
"node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
@@ -1522,150 +1529,160 @@
}
}
},
- "node_modules/@jest/core/node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/core/node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "node_modules/@jest/diff-sequences": {
+ "version": "30.0.1",
+ "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz",
+ "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==",
"dev": true,
"license": "MIT",
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
"engines": {
- "node": ">=8"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/environment": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz",
- "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.0.5.tgz",
+ "integrity": "sha512-aRX7WoaWx1oaOkDQvCWImVQ8XNtdv5sEWgk4gxR6NXb7WBUnL5sRak4WRzIQRZ1VTWPvV4VI4mgGjNL9TeKMYA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/fake-timers": "^29.7.0",
- "@jest/types": "^29.6.3",
+ "@jest/fake-timers": "30.0.5",
+ "@jest/types": "30.0.5",
"@types/node": "*",
- "jest-mock": "^29.7.0"
+ "jest-mock": "30.0.5"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/expect": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz",
- "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.0.5.tgz",
+ "integrity": "sha512-6udac8KKrtTtC+AXZ2iUN/R7dp7Ydry+Fo6FPFnDG54wjVMnb6vW/XNlf7Xj8UDjAE3aAVAsR4KFyKk3TCXmTA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "expect": "^29.7.0",
- "jest-snapshot": "^29.7.0"
+ "expect": "30.0.5",
+ "jest-snapshot": "30.0.5"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/expect-utils": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz",
- "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.0.5.tgz",
+ "integrity": "sha512-F3lmTT7CXWYywoVUGTCmom0vXq3HTTkaZyTAzIy+bXSBizB7o5qzlC9VCtq0arOa8GqmNsbg/cE9C6HLn7Szew==",
"dev": true,
"license": "MIT",
"dependencies": {
- "jest-get-type": "^29.6.3"
+ "@jest/get-type": "30.0.1"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/fake-timers": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz",
- "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.0.5.tgz",
+ "integrity": "sha512-ZO5DHfNV+kgEAeP3gK3XlpJLL4U3Sz6ebl/n68Uwt64qFFs5bv4bfEEjyRGK5uM0C90ewooNgFuKMdkbEoMEXw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/types": "^29.6.3",
- "@sinonjs/fake-timers": "^10.0.2",
+ "@jest/types": "30.0.5",
+ "@sinonjs/fake-timers": "^13.0.0",
"@types/node": "*",
- "jest-message-util": "^29.7.0",
- "jest-mock": "^29.7.0",
- "jest-util": "^29.7.0"
+ "jest-message-util": "30.0.5",
+ "jest-mock": "30.0.5",
+ "jest-util": "30.0.5"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/fake-timers/node_modules/@sinonjs/fake-timers": {
- "version": "10.3.0",
- "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz",
- "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==",
+ "version": "13.0.5",
+ "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz",
+ "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
- "@sinonjs/commons": "^3.0.0"
+ "@sinonjs/commons": "^3.0.1"
+ }
+ },
+ "node_modules/@jest/get-type": {
+ "version": "30.0.1",
+ "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.0.1.tgz",
+ "integrity": "sha512-AyYdemXCptSRFirI5EPazNxyPwAL0jXt3zceFjaj8NFiKP9pOi0bfXonf6qkf82z2t3QWPeLCWWw4stPBzctLw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz",
- "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.0.5.tgz",
+ "integrity": "sha512-7oEJT19WW4oe6HR7oLRvHxwlJk2gev0U9px3ufs8sX9PoD1Eza68KF0/tlN7X0dq/WVsBScXQGgCldA1V9Y/jA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/environment": "^29.7.0",
- "@jest/expect": "^29.7.0",
- "@jest/types": "^29.6.3",
- "jest-mock": "^29.7.0"
+ "@jest/environment": "30.0.5",
+ "@jest/expect": "30.0.5",
+ "@jest/types": "30.0.5",
+ "jest-mock": "30.0.5"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ }
+ },
+ "node_modules/@jest/pattern": {
+ "version": "30.0.1",
+ "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz",
+ "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*",
+ "jest-regex-util": "30.0.1"
+ },
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/reporters": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz",
- "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.0.5.tgz",
+ "integrity": "sha512-mafft7VBX4jzED1FwGC1o/9QUM2xebzavImZMeqnsklgcyxBto8mV4HzNSzUrryJ+8R9MFOM3HgYuDradWR+4g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@bcoe/v8-coverage": "^0.2.3",
- "@jest/console": "^29.7.0",
- "@jest/test-result": "^29.7.0",
- "@jest/transform": "^29.7.0",
- "@jest/types": "^29.6.3",
- "@jridgewell/trace-mapping": "^0.3.18",
+ "@jest/console": "30.0.5",
+ "@jest/test-result": "30.0.5",
+ "@jest/transform": "30.0.5",
+ "@jest/types": "30.0.5",
+ "@jridgewell/trace-mapping": "^0.3.25",
"@types/node": "*",
- "chalk": "^4.0.0",
- "collect-v8-coverage": "^1.0.0",
- "exit": "^0.1.2",
- "glob": "^7.1.3",
- "graceful-fs": "^4.2.9",
+ "chalk": "^4.1.2",
+ "collect-v8-coverage": "^1.0.2",
+ "exit-x": "^0.2.2",
+ "glob": "^10.3.10",
+ "graceful-fs": "^4.2.11",
"istanbul-lib-coverage": "^3.0.0",
"istanbul-lib-instrument": "^6.0.0",
"istanbul-lib-report": "^3.0.0",
- "istanbul-lib-source-maps": "^4.0.0",
+ "istanbul-lib-source-maps": "^5.0.0",
"istanbul-reports": "^3.1.3",
- "jest-message-util": "^29.7.0",
- "jest-util": "^29.7.0",
- "jest-worker": "^29.7.0",
+ "jest-message-util": "30.0.5",
+ "jest-util": "30.0.5",
+ "jest-worker": "30.0.5",
"slash": "^3.0.0",
- "string-length": "^4.0.1",
- "strip-ansi": "^6.0.0",
+ "string-length": "^4.0.2",
"v8-to-istanbul": "^9.0.1"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
},
"peerDependencies": {
"node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
@@ -1683,160 +1700,132 @@
"dev": true,
"license": "MIT"
},
- "node_modules/@jest/reporters/node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/reporters/node_modules/glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "deprecated": "Glob versions prior to v9 are no longer supported",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/@jest/reporters/node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "node_modules/@jest/schemas": {
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
+ "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "ansi-regex": "^5.0.1"
+ "@sinclair/typebox": "^0.34.0"
},
"engines": {
- "node": ">=8"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
- "node_modules/@jest/schemas": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
- "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
+ "node_modules/@jest/snapshot-utils": {
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.0.5.tgz",
+ "integrity": "sha512-XcCQ5qWHLvi29UUrowgDFvV4t7ETxX91CbDczMnoqXPOIcZOxyNdSjm6kV5XMc8+HkxfRegU/MUmnTbJRzGrUQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@sinclair/typebox": "^0.27.8"
+ "@jest/types": "30.0.5",
+ "chalk": "^4.1.2",
+ "graceful-fs": "^4.2.11",
+ "natural-compare": "^1.4.0"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/source-map": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz",
- "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==",
+ "version": "30.0.1",
+ "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz",
+ "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jridgewell/trace-mapping": "^0.3.18",
- "callsites": "^3.0.0",
- "graceful-fs": "^4.2.9"
+ "@jridgewell/trace-mapping": "^0.3.25",
+ "callsites": "^3.1.0",
+ "graceful-fs": "^4.2.11"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/test-result": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz",
- "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.0.5.tgz",
+ "integrity": "sha512-wPyztnK0gbDMQAJZ43tdMro+qblDHH1Ru/ylzUo21TBKqt88ZqnKKK2m30LKmLLoKtR2lxdpCC/P3g1vfKcawQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/console": "^29.7.0",
- "@jest/types": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "collect-v8-coverage": "^1.0.0"
+ "@jest/console": "30.0.5",
+ "@jest/types": "30.0.5",
+ "@types/istanbul-lib-coverage": "^2.0.6",
+ "collect-v8-coverage": "^1.0.2"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/test-sequencer": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz",
- "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.0.5.tgz",
+ "integrity": "sha512-Aea/G1egWoIIozmDD7PBXUOxkekXl7ueGzrsGGi1SbeKgQqCYCIf+wfbflEbf2LiPxL8j2JZGLyrzZagjvW4YQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/test-result": "^29.7.0",
- "graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.7.0",
+ "@jest/test-result": "30.0.5",
+ "graceful-fs": "^4.2.11",
+ "jest-haste-map": "30.0.5",
"slash": "^3.0.0"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/transform": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz",
- "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.0.5.tgz",
+ "integrity": "sha512-Vk8amLQCmuZyy6GbBht1Jfo9RSdBtg7Lks+B0PecnjI8J+PCLQPGh7uI8Q/2wwpW2gLdiAfiHNsmekKlywULqg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/core": "^7.11.6",
- "@jest/types": "^29.6.3",
- "@jridgewell/trace-mapping": "^0.3.18",
- "babel-plugin-istanbul": "^6.1.1",
- "chalk": "^4.0.0",
+ "@babel/core": "^7.27.4",
+ "@jest/types": "30.0.5",
+ "@jridgewell/trace-mapping": "^0.3.25",
+ "babel-plugin-istanbul": "^7.0.0",
+ "chalk": "^4.1.2",
"convert-source-map": "^2.0.0",
"fast-json-stable-stringify": "^2.1.0",
- "graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.7.0",
- "jest-regex-util": "^29.6.3",
- "jest-util": "^29.7.0",
- "micromatch": "^4.0.4",
- "pirates": "^4.0.4",
+ "graceful-fs": "^4.2.11",
+ "jest-haste-map": "30.0.5",
+ "jest-regex-util": "30.0.1",
+ "jest-util": "30.0.5",
+ "micromatch": "^4.0.8",
+ "pirates": "^4.0.7",
"slash": "^3.0.0",
- "write-file-atomic": "^4.0.2"
+ "write-file-atomic": "^5.0.1"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/types": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz",
- "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.0.5.tgz",
+ "integrity": "sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
+ "@jest/pattern": "30.0.1",
+ "@jest/schemas": "30.0.5",
+ "@types/istanbul-lib-coverage": "^2.0.6",
+ "@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
+ "@types/yargs": "^17.0.33",
+ "chalk": "^4.1.2"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jridgewell/gen-mapping": {
- "version": "0.3.12",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz",
- "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==",
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1855,16 +1844,16 @@
}
},
"node_modules/@jridgewell/sourcemap-codec": {
- "version": "1.5.4",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz",
- "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==",
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
- "version": "0.3.29",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz",
- "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==",
+ "version": "0.3.30",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz",
+ "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1886,6 +1875,20 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@metcoder95/https-pem": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@metcoder95/https-pem/-/https-pem-1.0.0.tgz",
+ "integrity": "sha512-v+nv59Y6SqdtbXBmAlVx++Vrc2DkBt4F7AVOmbNMB+pjD8QLCoReRdsTCydJC/wY4iZX8O4Cm0F1DhgDgwhIsg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "selfsigned": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
"node_modules/@napi-rs/wasm-runtime": {
"version": "0.2.12",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
@@ -1958,10 +1961,23 @@
"node": ">=14"
}
},
+ "node_modules/@pkgr/core": {
+ "version": "0.2.9",
+ "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz",
+ "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || ^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/pkgr"
+ }
+ },
"node_modules/@reporters/github": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/@reporters/github/-/github-1.8.0.tgz",
- "integrity": "sha512-EJNbv7qvqbICrVbyaPLKWT/mGzdkkdskKuPg1hG0tVKeAEtH6D1gCZwZ84N/26CQ8FBsyfiUyVjwtgYEByGKWQ==",
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@reporters/github/-/github-1.9.1.tgz",
+ "integrity": "sha512-MIuO3Ci0vCKV5CkueQOieiYKPqJvHkHJxYsk+raotCHcB4yPU4ns6yfy3tcXDsUFCkj+vbB+XXucdac139J6uA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1977,9 +1993,9 @@
"license": "MIT"
},
"node_modules/@sinclair/typebox": {
- "version": "0.27.8",
- "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
- "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
+ "version": "0.34.40",
+ "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.40.tgz",
+ "integrity": "sha512-gwBNIP8ZAYev/ORDWW0QvxdwPXwxBtLsdsJgSc7eDIRt8ubP+rxUBzPsrwnu16fgEF8Bx4lh/+mvQvJzcTM6Kw==",
"dev": true,
"license": "MIT"
},
@@ -2050,9 +2066,9 @@
}
},
"node_modules/@tsd/typescript": {
- "version": "5.8.3",
- "resolved": "https://registry.npmjs.org/@tsd/typescript/-/typescript-5.8.3.tgz",
- "integrity": "sha512-oKarNCN1QUhG148M88mtZdOlBZWWGcInquef+U8QL7gwJkRuNo5WS45Fjsd+3hM9cDJWGpqSZ4Oo097KDx4IWA==",
+ "version": "5.9.2",
+ "resolved": "https://registry.npmjs.org/@tsd/typescript/-/typescript-5.9.2.tgz",
+ "integrity": "sha512-mSMM0QtEPdMd+rdMDd17yCUYD4yI3pKHap89+jEZrZ3KIO5PhDofBjER0OtgHdvOXF74KMLO3fyD6k3Hz0v03A==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2133,16 +2149,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/@types/graceful-fs": {
- "version": "4.1.9",
- "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
- "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/node": "*"
- }
- },
"node_modules/@types/istanbul-lib-coverage": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
@@ -2185,25 +2191,15 @@
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "18.19.121",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.121.tgz",
- "integrity": "sha512-bHOrbyztmyYIi4f1R0s17QsPs1uyyYnGcXeZoGEd227oZjry0q6XQBQxd82X1I57zEfwO8h9Xo+Kl5gX1d9MwQ==",
+ "version": "18.19.123",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.123.tgz",
+ "integrity": "sha512-K7DIaHnh0mzVxreCR9qwgNxp3MH9dltPNIEddW9MYUlcKAzm+3grKNSTe2vCJHI1FaLpvpL5JGJrz1UZDKYvDg==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~5.26.4"
}
},
- "node_modules/@types/node-forge": {
- "version": "1.3.13",
- "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.13.tgz",
- "integrity": "sha512-zePQJSW5QkwSHKRApqWCVKeKoSOt4xvEnLENZPjyvm9Ezdf/EyDeJM7jqLzOwjVICQQzvLZ63T55MKdJB5H6ww==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/node": "*"
- }
- },
"node_modules/@types/normalize-package-data": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz",
@@ -2236,17 +2232,17 @@
"license": "MIT"
},
"node_modules/@typescript-eslint/eslint-plugin": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.38.0.tgz",
- "integrity": "sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==",
+ "version": "8.39.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.39.1.tgz",
+ "integrity": "sha512-yYegZ5n3Yr6eOcqgj2nJH8cH/ZZgF+l0YIdKILSDjYFRjgYQMgv/lRjV5Z7Up04b9VYUondt8EPMqg7kTWgJ2g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.10.0",
- "@typescript-eslint/scope-manager": "8.38.0",
- "@typescript-eslint/type-utils": "8.38.0",
- "@typescript-eslint/utils": "8.38.0",
- "@typescript-eslint/visitor-keys": "8.38.0",
+ "@typescript-eslint/scope-manager": "8.39.1",
+ "@typescript-eslint/type-utils": "8.39.1",
+ "@typescript-eslint/utils": "8.39.1",
+ "@typescript-eslint/visitor-keys": "8.39.1",
"graphemer": "^1.4.0",
"ignore": "^7.0.0",
"natural-compare": "^1.4.0",
@@ -2260,9 +2256,9 @@
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
- "@typescript-eslint/parser": "^8.38.0",
+ "@typescript-eslint/parser": "^8.39.1",
"eslint": "^8.57.0 || ^9.0.0",
- "typescript": ">=4.8.4 <5.9.0"
+ "typescript": ">=4.8.4 <6.0.0"
}
},
"node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
@@ -2276,16 +2272,16 @@
}
},
"node_modules/@typescript-eslint/parser": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.38.0.tgz",
- "integrity": "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==",
+ "version": "8.39.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.39.1.tgz",
+ "integrity": "sha512-pUXGCuHnnKw6PyYq93lLRiZm3vjuslIy7tus1lIQTYVK9bL8XBgJnCWm8a0KcTtHC84Yya1Q6rtll+duSMj0dg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/scope-manager": "8.38.0",
- "@typescript-eslint/types": "8.38.0",
- "@typescript-eslint/typescript-estree": "8.38.0",
- "@typescript-eslint/visitor-keys": "8.38.0",
+ "@typescript-eslint/scope-manager": "8.39.1",
+ "@typescript-eslint/types": "8.39.1",
+ "@typescript-eslint/typescript-estree": "8.39.1",
+ "@typescript-eslint/visitor-keys": "8.39.1",
"debug": "^4.3.4"
},
"engines": {
@@ -2297,18 +2293,18 @@
},
"peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0",
- "typescript": ">=4.8.4 <5.9.0"
+ "typescript": ">=4.8.4 <6.0.0"
}
},
"node_modules/@typescript-eslint/project-service": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.38.0.tgz",
- "integrity": "sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==",
+ "version": "8.39.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.39.1.tgz",
+ "integrity": "sha512-8fZxek3ONTwBu9ptw5nCKqZOSkXshZB7uAxuFF0J/wTMkKydjXCzqqga7MlFMpHi9DoG4BadhmTkITBcg8Aybw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/tsconfig-utils": "^8.38.0",
- "@typescript-eslint/types": "^8.38.0",
+ "@typescript-eslint/tsconfig-utils": "^8.39.1",
+ "@typescript-eslint/types": "^8.39.1",
"debug": "^4.3.4"
},
"engines": {
@@ -2319,18 +2315,18 @@
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
- "typescript": ">=4.8.4 <5.9.0"
+ "typescript": ">=4.8.4 <6.0.0"
}
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.38.0.tgz",
- "integrity": "sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==",
+ "version": "8.39.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.39.1.tgz",
+ "integrity": "sha512-RkBKGBrjgskFGWuyUGz/EtD8AF/GW49S21J8dvMzpJitOF1slLEbbHnNEtAHtnDAnx8qDEdRrULRnWVx27wGBw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.38.0",
- "@typescript-eslint/visitor-keys": "8.38.0"
+ "@typescript-eslint/types": "8.39.1",
+ "@typescript-eslint/visitor-keys": "8.39.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2341,9 +2337,9 @@
}
},
"node_modules/@typescript-eslint/tsconfig-utils": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.38.0.tgz",
- "integrity": "sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==",
+ "version": "8.39.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.39.1.tgz",
+ "integrity": "sha512-ePUPGVtTMR8XMU2Hee8kD0Pu4NDE1CN9Q1sxGSGd/mbOtGZDM7pnhXNJnzW63zk/q+Z54zVzj44HtwXln5CvHA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2354,19 +2350,19 @@
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
- "typescript": ">=4.8.4 <5.9.0"
+ "typescript": ">=4.8.4 <6.0.0"
}
},
"node_modules/@typescript-eslint/type-utils": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.38.0.tgz",
- "integrity": "sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==",
+ "version": "8.39.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.39.1.tgz",
+ "integrity": "sha512-gu9/ahyatyAdQbKeHnhT4R+y3YLtqqHyvkfDxaBYk97EcbfChSJXyaJnIL3ygUv7OuZatePHmQvuH5ru0lnVeA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.38.0",
- "@typescript-eslint/typescript-estree": "8.38.0",
- "@typescript-eslint/utils": "8.38.0",
+ "@typescript-eslint/types": "8.39.1",
+ "@typescript-eslint/typescript-estree": "8.39.1",
+ "@typescript-eslint/utils": "8.39.1",
"debug": "^4.3.4",
"ts-api-utils": "^2.1.0"
},
@@ -2379,13 +2375,13 @@
},
"peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0",
- "typescript": ">=4.8.4 <5.9.0"
+ "typescript": ">=4.8.4 <6.0.0"
}
},
"node_modules/@typescript-eslint/types": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.38.0.tgz",
- "integrity": "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==",
+ "version": "8.39.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.39.1.tgz",
+ "integrity": "sha512-7sPDKQQp+S11laqTrhHqeAbsCfMkwJMrV7oTDvtDds4mEofJYir414bYKUEb8YPUm9QL3U+8f6L6YExSoAGdQw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2397,16 +2393,16 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.38.0.tgz",
- "integrity": "sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==",
+ "version": "8.39.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.39.1.tgz",
+ "integrity": "sha512-EKkpcPuIux48dddVDXyQBlKdeTPMmALqBUbEk38McWv0qVEZwOpVJBi7ugK5qVNgeuYjGNQxrrnoM/5+TI/BPw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/project-service": "8.38.0",
- "@typescript-eslint/tsconfig-utils": "8.38.0",
- "@typescript-eslint/types": "8.38.0",
- "@typescript-eslint/visitor-keys": "8.38.0",
+ "@typescript-eslint/project-service": "8.39.1",
+ "@typescript-eslint/tsconfig-utils": "8.39.1",
+ "@typescript-eslint/types": "8.39.1",
+ "@typescript-eslint/visitor-keys": "8.39.1",
"debug": "^4.3.4",
"fast-glob": "^3.3.2",
"is-glob": "^4.0.3",
@@ -2422,7 +2418,7 @@
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
- "typescript": ">=4.8.4 <5.9.0"
+ "typescript": ">=4.8.4 <6.0.0"
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
@@ -2465,16 +2461,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.38.0.tgz",
- "integrity": "sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==",
+ "version": "8.39.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.39.1.tgz",
+ "integrity": "sha512-VF5tZ2XnUSTuiqZFXCZfZs1cgkdd3O/sSYmdo2EpSyDlC86UM/8YytTmKnehOW3TGAlivqTDT6bS87B/GQ/jyg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.7.0",
- "@typescript-eslint/scope-manager": "8.38.0",
- "@typescript-eslint/types": "8.38.0",
- "@typescript-eslint/typescript-estree": "8.38.0"
+ "@typescript-eslint/scope-manager": "8.39.1",
+ "@typescript-eslint/types": "8.39.1",
+ "@typescript-eslint/typescript-estree": "8.39.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2485,17 +2481,17 @@
},
"peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0",
- "typescript": ">=4.8.4 <5.9.0"
+ "typescript": ">=4.8.4 <6.0.0"
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.38.0.tgz",
- "integrity": "sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==",
+ "version": "8.39.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.39.1.tgz",
+ "integrity": "sha512-W8FQi6kEh2e8zVhQ0eeRnxdvIoOkAp/CPAahcNio6nO9dsIwb9b34z90KOlheoyuVf6LSOEdjlkxSkapNEc+4A==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.38.0",
+ "@typescript-eslint/types": "8.39.1",
"eslint-visitor-keys": "^4.2.1"
},
"engines": {
@@ -2506,6 +2502,13 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
+ "node_modules/@ungap/structured-clone": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
+ "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/@unrs/resolver-binding-android-arm-eabi": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz",
@@ -2845,9 +2848,9 @@
}
},
"node_modules/ansi-regex": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
- "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.0.tgz",
+ "integrity": "sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -3193,42 +3196,42 @@
}
},
"node_modules/babel-jest": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz",
- "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.0.5.tgz",
+ "integrity": "sha512-mRijnKimhGDMsizTvBTWotwNpzrkHr+VvZUQBof2AufXKB8NXrL1W69TG20EvOz7aevx6FTJIaBuBkYxS8zolg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/transform": "^29.7.0",
- "@types/babel__core": "^7.1.14",
- "babel-plugin-istanbul": "^6.1.1",
- "babel-preset-jest": "^29.6.3",
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.9",
+ "@jest/transform": "30.0.5",
+ "@types/babel__core": "^7.20.5",
+ "babel-plugin-istanbul": "^7.0.0",
+ "babel-preset-jest": "30.0.1",
+ "chalk": "^4.1.2",
+ "graceful-fs": "^4.2.11",
"slash": "^3.0.0"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
},
"peerDependencies": {
- "@babel/core": "^7.8.0"
+ "@babel/core": "^7.11.0"
}
},
"node_modules/babel-plugin-istanbul": {
- "version": "6.1.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz",
- "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.0.tgz",
+ "integrity": "sha512-C5OzENSx/A+gt7t4VH1I2XsflxyPUmXRFPKBxt33xncdOmq7oROVM3bZv9Ysjjkv8OJYDMa+tKuKMvqU/H3xdw==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"@babel/helper-plugin-utils": "^7.0.0",
"@istanbuljs/load-nyc-config": "^1.0.0",
- "@istanbuljs/schema": "^0.1.2",
- "istanbul-lib-instrument": "^5.0.4",
+ "@istanbuljs/schema": "^0.1.3",
+ "istanbul-lib-instrument": "^6.0.2",
"test-exclude": "^6.0.0"
},
"engines": {
- "node": ">=8"
+ "node": ">=12"
}
},
"node_modules/babel-plugin-istanbul/node_modules/glob": {
@@ -3253,23 +3256,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
- "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
- "dev": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "@babel/core": "^7.12.3",
- "@babel/parser": "^7.14.7",
- "@istanbuljs/schema": "^0.1.2",
- "istanbul-lib-coverage": "^3.2.0",
- "semver": "^6.3.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/babel-plugin-istanbul/node_modules/test-exclude": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
@@ -3286,19 +3272,18 @@
}
},
"node_modules/babel-plugin-jest-hoist": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz",
- "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==",
+ "version": "30.0.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.0.1.tgz",
+ "integrity": "sha512-zTPME3pI50NsFW8ZBaVIOeAxzEY7XHlmWeXXu9srI+9kNfzCUTy8MFan46xOGZY8NZThMqq+e3qZUKsvXbasnQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/template": "^7.3.3",
- "@babel/types": "^7.3.3",
- "@types/babel__core": "^7.1.14",
- "@types/babel__traverse": "^7.0.6"
+ "@babel/template": "^7.27.2",
+ "@babel/types": "^7.27.3",
+ "@types/babel__core": "^7.20.5"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/babel-preset-current-node-syntax": {
@@ -3329,20 +3314,20 @@
}
},
"node_modules/babel-preset-jest": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz",
- "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==",
+ "version": "30.0.1",
+ "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.0.1.tgz",
+ "integrity": "sha512-+YHejD5iTWI46cZmcc/YtX4gaKBtdqCHCVfuVinizVpbmyjO3zYmeuyFdfA8duRqQZfgCAMlsfmkVbJ+e2MAJw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "babel-plugin-jest-hoist": "^29.6.3",
- "babel-preset-current-node-syntax": "^1.0.0"
+ "babel-plugin-jest-hoist": "30.0.1",
+ "babel-preset-current-node-syntax": "^1.1.0"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
},
"peerDependencies": {
- "@babel/core": "^7.0.0"
+ "@babel/core": "^7.11.0"
}
},
"node_modules/balanced-match": {
@@ -3401,9 +3386,9 @@
}
},
"node_modules/browserslist": {
- "version": "4.25.1",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz",
- "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==",
+ "version": "4.25.2",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.2.tgz",
+ "integrity": "sha512-0si2SJK3ooGzIawRu61ZdPCO1IncZwS8IzuX73sPZsXW6EQ/w/DAfPyKI8l1ETTCr2MnvqWitmlCUxgdul45jA==",
"dev": true,
"funding": [
{
@@ -3421,8 +3406,8 @@
],
"license": "MIT",
"dependencies": {
- "caniuse-lite": "^1.0.30001726",
- "electron-to-chromium": "^1.5.173",
+ "caniuse-lite": "^1.0.30001733",
+ "electron-to-chromium": "^1.5.199",
"node-releases": "^2.0.19",
"update-browserslist-db": "^1.1.3"
},
@@ -3632,9 +3617,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001731",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz",
- "integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==",
+ "version": "1.0.30001735",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001735.tgz",
+ "integrity": "sha512-EV/laoX7Wq2J9TQlyIXRxTJqIw4sxfXS4OYgudGxBYRuTv0q7AM6yMEpU/Vo1I94thg9U6EZ2NfZx9GJq83u7w==",
"dev": true,
"funding": [
{
@@ -3680,9 +3665,9 @@
}
},
"node_modules/ci-info": {
- "version": "3.9.0",
- "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
- "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==",
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.0.tgz",
+ "integrity": "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==",
"dev": true,
"funding": [
{
@@ -3696,9 +3681,9 @@
}
},
"node_modules/cjs-module-lexer": {
- "version": "1.4.3",
- "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz",
- "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.0.tgz",
+ "integrity": "sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA==",
"dev": true,
"license": "MIT"
},
@@ -3842,45 +3827,22 @@
"dev": true,
"license": "MIT"
},
- "node_modules/create-jest": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz",
- "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@jest/types": "^29.6.3",
- "chalk": "^4.0.0",
- "exit": "^0.1.2",
- "graceful-fs": "^4.2.9",
- "jest-config": "^29.7.0",
- "jest-util": "^29.7.0",
- "prompts": "^2.0.1"
- },
- "bin": {
- "create-jest": "bin/create-jest.js"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
"node_modules/cross-env": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
- "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.0.0.tgz",
+ "integrity": "sha512-aU8qlEK/nHYtVuN4p7UQgAwVljzMg8hB4YK5ThRqD2l/ziSnryncPNn7bMLt5cFYsKVKBh8HqLqyCoTupEUu7Q==",
"dev": true,
"license": "MIT",
"dependencies": {
- "cross-spawn": "^7.0.1"
+ "@epic-web/invariant": "^1.0.0",
+ "cross-spawn": "^7.0.6"
},
"bin": {
- "cross-env": "src/bin/cross-env.js",
- "cross-env-shell": "src/bin/cross-env-shell.js"
+ "cross-env": "dist/bin/cross-env.js",
+ "cross-env-shell": "dist/bin/cross-env-shell.js"
},
"engines": {
- "node": ">=10.14",
- "npm": ">=6",
- "yarn": ">=1"
+ "node": ">=20"
}
},
"node_modules/cross-spawn": {
@@ -4157,9 +4119,9 @@
"license": "MIT"
},
"node_modules/electron-to-chromium": {
- "version": "1.5.194",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.194.tgz",
- "integrity": "sha512-SdnWJwSUot04UR51I2oPD8kuP2VI37/CADR1OHsFOUzZIvfWJBO6q11k5P/uKNyTT3cdOsnyjkrZ+DDShqYqJA==",
+ "version": "1.5.203",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.203.tgz",
+ "integrity": "sha512-uz4i0vLhfm6dLZWbz/iH88KNDV+ivj5+2SA+utpgjKaj9Q0iDLuwk6Idhe9BTxciHudyx6IvTvijhkPvFGUQ0g==",
"dev": true,
"license": "ISC"
},
@@ -4184,9 +4146,9 @@
"license": "MIT"
},
"node_modules/enhanced-resolve": {
- "version": "5.18.2",
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz",
- "integrity": "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==",
+ "version": "5.18.3",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
+ "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4385,9 +4347,9 @@
}
},
"node_modules/esbuild": {
- "version": "0.25.8",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz",
- "integrity": "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==",
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz",
+ "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -4398,32 +4360,32 @@
"node": ">=18"
},
"optionalDependencies": {
- "@esbuild/aix-ppc64": "0.25.8",
- "@esbuild/android-arm": "0.25.8",
- "@esbuild/android-arm64": "0.25.8",
- "@esbuild/android-x64": "0.25.8",
- "@esbuild/darwin-arm64": "0.25.8",
- "@esbuild/darwin-x64": "0.25.8",
- "@esbuild/freebsd-arm64": "0.25.8",
- "@esbuild/freebsd-x64": "0.25.8",
- "@esbuild/linux-arm": "0.25.8",
- "@esbuild/linux-arm64": "0.25.8",
- "@esbuild/linux-ia32": "0.25.8",
- "@esbuild/linux-loong64": "0.25.8",
- "@esbuild/linux-mips64el": "0.25.8",
- "@esbuild/linux-ppc64": "0.25.8",
- "@esbuild/linux-riscv64": "0.25.8",
- "@esbuild/linux-s390x": "0.25.8",
- "@esbuild/linux-x64": "0.25.8",
- "@esbuild/netbsd-arm64": "0.25.8",
- "@esbuild/netbsd-x64": "0.25.8",
- "@esbuild/openbsd-arm64": "0.25.8",
- "@esbuild/openbsd-x64": "0.25.8",
- "@esbuild/openharmony-arm64": "0.25.8",
- "@esbuild/sunos-x64": "0.25.8",
- "@esbuild/win32-arm64": "0.25.8",
- "@esbuild/win32-ia32": "0.25.8",
- "@esbuild/win32-x64": "0.25.8"
+ "@esbuild/aix-ppc64": "0.25.9",
+ "@esbuild/android-arm": "0.25.9",
+ "@esbuild/android-arm64": "0.25.9",
+ "@esbuild/android-x64": "0.25.9",
+ "@esbuild/darwin-arm64": "0.25.9",
+ "@esbuild/darwin-x64": "0.25.9",
+ "@esbuild/freebsd-arm64": "0.25.9",
+ "@esbuild/freebsd-x64": "0.25.9",
+ "@esbuild/linux-arm": "0.25.9",
+ "@esbuild/linux-arm64": "0.25.9",
+ "@esbuild/linux-ia32": "0.25.9",
+ "@esbuild/linux-loong64": "0.25.9",
+ "@esbuild/linux-mips64el": "0.25.9",
+ "@esbuild/linux-ppc64": "0.25.9",
+ "@esbuild/linux-riscv64": "0.25.9",
+ "@esbuild/linux-s390x": "0.25.9",
+ "@esbuild/linux-x64": "0.25.9",
+ "@esbuild/netbsd-arm64": "0.25.9",
+ "@esbuild/netbsd-x64": "0.25.9",
+ "@esbuild/openbsd-arm64": "0.25.9",
+ "@esbuild/openbsd-x64": "0.25.9",
+ "@esbuild/openharmony-arm64": "0.25.9",
+ "@esbuild/sunos-x64": "0.25.9",
+ "@esbuild/win32-arm64": "0.25.9",
+ "@esbuild/win32-ia32": "0.25.9",
+ "@esbuild/win32-x64": "0.25.9"
}
},
"node_modules/escalade": {
@@ -4450,20 +4412,20 @@
}
},
"node_modules/eslint": {
- "version": "9.32.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.32.0.tgz",
- "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==",
+ "version": "9.33.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.33.0.tgz",
+ "integrity": "sha512-TS9bTNIryDzStCpJN93aC5VRSW3uTx9sClUn4B87pwiCaJh220otoI0X8mJKr+VcPtniMdN8GKjlwgWGUv5ZKA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1",
"@eslint/config-array": "^0.21.0",
- "@eslint/config-helpers": "^0.3.0",
- "@eslint/core": "^0.15.0",
+ "@eslint/config-helpers": "^0.3.1",
+ "@eslint/core": "^0.15.2",
"@eslint/eslintrc": "^3.3.1",
- "@eslint/js": "9.32.0",
- "@eslint/plugin-kit": "^0.3.4",
+ "@eslint/js": "9.33.0",
+ "@eslint/plugin-kit": "^0.3.5",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.4.2",
@@ -4860,24 +4822,6 @@
"eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7"
}
},
- "node_modules/eslint-plugin-react/node_modules/resolve": {
- "version": "2.0.0-next.5",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
- "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-core-module": "^2.13.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- },
- "bin": {
- "resolve": "bin/resolve"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/eslint-rule-docs": {
"version": "1.1.235",
"resolved": "https://registry.npmjs.org/eslint-rule-docs/-/eslint-rule-docs-1.1.235.tgz",
@@ -5089,30 +5033,32 @@
"url": "https://github.com/sindresorhus/execa?sponsor=1"
}
},
- "node_modules/exit": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
- "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
+ "node_modules/exit-x": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz",
+ "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/expect": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz",
- "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/expect/-/expect-30.0.5.tgz",
+ "integrity": "sha512-P0te2pt+hHI5qLJkIR+iMvS+lYUZml8rKKsohVHAGY+uClp9XVbdyYNJOIjSRpHVp8s8YqxJCiHUkSYZGr8rtQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/expect-utils": "^29.7.0",
- "jest-get-type": "^29.6.3",
- "jest-matcher-utils": "^29.7.0",
- "jest-message-util": "^29.7.0",
- "jest-util": "^29.7.0"
+ "@jest/expect-utils": "30.0.5",
+ "@jest/get-type": "30.0.1",
+ "jest-matcher-utils": "30.0.5",
+ "jest-message-util": "30.0.5",
+ "jest-mock": "30.0.5",
+ "jest-util": "30.0.5"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/fast-check": {
@@ -5792,17 +5738,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/https-pem": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/https-pem/-/https-pem-3.0.0.tgz",
- "integrity": "sha512-JqYVRTpk1WeXziwBaTX6eyXod6Dt70d/kehtY3DR6ygl+11XgcksTjSl4NjZbNCKK3rpTB1qH9hnu75RSOFUWQ==",
- "dev": true,
- "hasInstallScript": true,
- "license": "MIT",
- "dependencies": {
- "selfsigned": "^2.0.1"
- }
- },
"node_modules/human-signals": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz",
@@ -6490,15 +6425,15 @@
}
},
"node_modules/istanbul-lib-source-maps": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
- "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz",
+ "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
+ "@jridgewell/trace-mapping": "^0.3.23",
"debug": "^4.1.1",
- "istanbul-lib-coverage": "^3.0.0",
- "source-map": "^0.6.1"
+ "istanbul-lib-coverage": "^3.0.0"
},
"engines": {
"node": ">=10"
@@ -6553,22 +6488,22 @@
}
},
"node_modules/jest": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz",
- "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest/-/jest-30.0.5.tgz",
+ "integrity": "sha512-y2mfcJywuTUkvLm2Lp1/pFX8kTgMO5yyQGq/Sk/n2mN7XWYp4JsCZ/QXW34M8YScgk8bPZlREH04f6blPnoHnQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/core": "^29.7.0",
- "@jest/types": "^29.6.3",
- "import-local": "^3.0.2",
- "jest-cli": "^29.7.0"
+ "@jest/core": "30.0.5",
+ "@jest/types": "30.0.5",
+ "import-local": "^3.2.0",
+ "jest-cli": "30.0.5"
},
"bin": {
"jest": "bin/jest.js"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
},
"peerDependencies": {
"node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
@@ -6580,18 +6515,18 @@
}
},
"node_modules/jest-changed-files": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz",
- "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.0.5.tgz",
+ "integrity": "sha512-bGl2Ntdx0eAwXuGpdLdVYVr5YQHnSZlQ0y9HVDu565lCUAe9sj6JOtBbMmBBikGIegne9piDDIOeiLVoqTkz4A==",
"dev": true,
"license": "MIT",
"dependencies": {
- "execa": "^5.0.0",
- "jest-util": "^29.7.0",
+ "execa": "^5.1.1",
+ "jest-util": "30.0.5",
"p-limit": "^3.1.0"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-changed-files/node_modules/execa": {
@@ -6685,78 +6620,60 @@
}
},
"node_modules/jest-circus": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz",
- "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.0.5.tgz",
+ "integrity": "sha512-h/sjXEs4GS+NFFfqBDYT7y5Msfxh04EwWLhQi0F8kuWpe+J/7tICSlswU8qvBqumR3kFgHbfu7vU6qruWWBPug==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/environment": "^29.7.0",
- "@jest/expect": "^29.7.0",
- "@jest/test-result": "^29.7.0",
- "@jest/types": "^29.6.3",
+ "@jest/environment": "30.0.5",
+ "@jest/expect": "30.0.5",
+ "@jest/test-result": "30.0.5",
+ "@jest/types": "30.0.5",
"@types/node": "*",
- "chalk": "^4.0.0",
+ "chalk": "^4.1.2",
"co": "^4.6.0",
- "dedent": "^1.0.0",
- "is-generator-fn": "^2.0.0",
- "jest-each": "^29.7.0",
- "jest-matcher-utils": "^29.7.0",
- "jest-message-util": "^29.7.0",
- "jest-runtime": "^29.7.0",
- "jest-snapshot": "^29.7.0",
- "jest-util": "^29.7.0",
+ "dedent": "^1.6.0",
+ "is-generator-fn": "^2.1.0",
+ "jest-each": "30.0.5",
+ "jest-matcher-utils": "30.0.5",
+ "jest-message-util": "30.0.5",
+ "jest-runtime": "30.0.5",
+ "jest-snapshot": "30.0.5",
+ "jest-util": "30.0.5",
"p-limit": "^3.1.0",
- "pretty-format": "^29.7.0",
- "pure-rand": "^6.0.0",
+ "pretty-format": "30.0.5",
+ "pure-rand": "^7.0.0",
"slash": "^3.0.0",
- "stack-utils": "^2.0.3"
+ "stack-utils": "^2.0.6"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
- "node_modules/jest-circus/node_modules/pure-rand": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz",
- "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==",
- "dev": true,
- "funding": [
- {
- "type": "individual",
- "url": "https://github.com/sponsors/dubzzz"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/fast-check"
- }
- ],
- "license": "MIT"
- },
"node_modules/jest-cli": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz",
- "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.0.5.tgz",
+ "integrity": "sha512-Sa45PGMkBZzF94HMrlX4kUyPOwUpdZasaliKN3mifvDmkhLYqLLg8HQTzn6gq7vJGahFYMQjXgyJWfYImKZzOw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/core": "^29.7.0",
- "@jest/test-result": "^29.7.0",
- "@jest/types": "^29.6.3",
- "chalk": "^4.0.0",
- "create-jest": "^29.7.0",
- "exit": "^0.1.2",
- "import-local": "^3.0.2",
- "jest-config": "^29.7.0",
- "jest-util": "^29.7.0",
- "jest-validate": "^29.7.0",
- "yargs": "^17.3.1"
+ "@jest/core": "30.0.5",
+ "@jest/test-result": "30.0.5",
+ "@jest/types": "30.0.5",
+ "chalk": "^4.1.2",
+ "exit-x": "^0.2.2",
+ "import-local": "^3.2.0",
+ "jest-config": "30.0.5",
+ "jest-util": "30.0.5",
+ "jest-validate": "30.0.5",
+ "yargs": "^17.7.2"
},
"bin": {
"jest": "bin/jest.js"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
},
"peerDependencies": {
"node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
@@ -6768,135 +6685,120 @@
}
},
"node_modules/jest-config": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz",
- "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.0.5.tgz",
+ "integrity": "sha512-aIVh+JNOOpzUgzUnPn5FLtyVnqc3TQHVMupYtyeURSb//iLColiMIR8TxCIDKyx9ZgjKnXGucuW68hCxgbrwmA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/core": "^7.11.6",
- "@jest/test-sequencer": "^29.7.0",
- "@jest/types": "^29.6.3",
- "babel-jest": "^29.7.0",
- "chalk": "^4.0.0",
- "ci-info": "^3.2.0",
- "deepmerge": "^4.2.2",
- "glob": "^7.1.3",
- "graceful-fs": "^4.2.9",
- "jest-circus": "^29.7.0",
- "jest-environment-node": "^29.7.0",
- "jest-get-type": "^29.6.3",
- "jest-regex-util": "^29.6.3",
- "jest-resolve": "^29.7.0",
- "jest-runner": "^29.7.0",
- "jest-util": "^29.7.0",
- "jest-validate": "^29.7.0",
- "micromatch": "^4.0.4",
+ "@babel/core": "^7.27.4",
+ "@jest/get-type": "30.0.1",
+ "@jest/pattern": "30.0.1",
+ "@jest/test-sequencer": "30.0.5",
+ "@jest/types": "30.0.5",
+ "babel-jest": "30.0.5",
+ "chalk": "^4.1.2",
+ "ci-info": "^4.2.0",
+ "deepmerge": "^4.3.1",
+ "glob": "^10.3.10",
+ "graceful-fs": "^4.2.11",
+ "jest-circus": "30.0.5",
+ "jest-docblock": "30.0.1",
+ "jest-environment-node": "30.0.5",
+ "jest-regex-util": "30.0.1",
+ "jest-resolve": "30.0.5",
+ "jest-runner": "30.0.5",
+ "jest-util": "30.0.5",
+ "jest-validate": "30.0.5",
+ "micromatch": "^4.0.8",
"parse-json": "^5.2.0",
- "pretty-format": "^29.7.0",
+ "pretty-format": "30.0.5",
"slash": "^3.0.0",
"strip-json-comments": "^3.1.1"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
},
"peerDependencies": {
"@types/node": "*",
+ "esbuild-register": ">=3.4.0",
"ts-node": ">=9.0.0"
},
"peerDependenciesMeta": {
"@types/node": {
"optional": true
},
+ "esbuild-register": {
+ "optional": true
+ },
"ts-node": {
"optional": true
}
}
},
- "node_modules/jest-config/node_modules/glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "deprecated": "Glob versions prior to v9 are no longer supported",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
"node_modules/jest-diff": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz",
- "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.0.5.tgz",
+ "integrity": "sha512-1UIqE9PoEKaHcIKvq2vbibrCog4Y8G0zmOxgQUVEiTqwR5hJVMCoDsN1vFvI5JvwD37hjueZ1C4l2FyGnfpE0A==",
"dev": true,
"license": "MIT",
"dependencies": {
- "chalk": "^4.0.0",
- "diff-sequences": "^29.6.3",
- "jest-get-type": "^29.6.3",
- "pretty-format": "^29.7.0"
+ "@jest/diff-sequences": "30.0.1",
+ "@jest/get-type": "30.0.1",
+ "chalk": "^4.1.2",
+ "pretty-format": "30.0.5"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-docblock": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz",
- "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==",
+ "version": "30.0.1",
+ "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.0.1.tgz",
+ "integrity": "sha512-/vF78qn3DYphAaIc3jy4gA7XSAz167n9Bm/wn/1XhTLW7tTBIzXtCJpb/vcmc73NIIeeohCbdL94JasyXUZsGA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "detect-newline": "^3.0.0"
+ "detect-newline": "^3.1.0"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-each": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz",
- "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.0.5.tgz",
+ "integrity": "sha512-dKjRsx1uZ96TVyejD3/aAWcNKy6ajMaN531CwWIsrazIqIoXI9TnnpPlkrEYku/8rkS3dh2rbH+kMOyiEIv0xQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/types": "^29.6.3",
- "chalk": "^4.0.0",
- "jest-get-type": "^29.6.3",
- "jest-util": "^29.7.0",
- "pretty-format": "^29.7.0"
+ "@jest/get-type": "30.0.1",
+ "@jest/types": "30.0.5",
+ "chalk": "^4.1.2",
+ "jest-util": "30.0.5",
+ "pretty-format": "30.0.5"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-environment-node": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz",
- "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.0.5.tgz",
+ "integrity": "sha512-ppYizXdLMSvciGsRsMEnv/5EFpvOdXBaXRBzFUDPWrsfmog4kYrOGWXarLllz6AXan6ZAA/kYokgDWuos1IKDA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/environment": "^29.7.0",
- "@jest/fake-timers": "^29.7.0",
- "@jest/types": "^29.6.3",
+ "@jest/environment": "30.0.5",
+ "@jest/fake-timers": "30.0.5",
+ "@jest/types": "30.0.5",
"@types/node": "*",
- "jest-mock": "^29.7.0",
- "jest-util": "^29.7.0"
+ "jest-mock": "30.0.5",
+ "jest-util": "30.0.5",
+ "jest-validate": "30.0.5"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-get-type": {
@@ -6910,95 +6812,94 @@
}
},
"node_modules/jest-haste-map": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz",
- "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.0.5.tgz",
+ "integrity": "sha512-dkmlWNlsTSR0nH3nRfW5BKbqHefLZv0/6LCccG0xFCTWcJu8TuEwG+5Cm75iBfjVoockmO6J35o5gxtFSn5xeg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/types": "^29.6.3",
- "@types/graceful-fs": "^4.1.3",
+ "@jest/types": "30.0.5",
"@types/node": "*",
- "anymatch": "^3.0.3",
- "fb-watchman": "^2.0.0",
- "graceful-fs": "^4.2.9",
- "jest-regex-util": "^29.6.3",
- "jest-util": "^29.7.0",
- "jest-worker": "^29.7.0",
- "micromatch": "^4.0.4",
+ "anymatch": "^3.1.3",
+ "fb-watchman": "^2.0.2",
+ "graceful-fs": "^4.2.11",
+ "jest-regex-util": "30.0.1",
+ "jest-util": "30.0.5",
+ "jest-worker": "30.0.5",
+ "micromatch": "^4.0.8",
"walker": "^1.0.8"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
},
"optionalDependencies": {
- "fsevents": "^2.3.2"
+ "fsevents": "^2.3.3"
}
},
"node_modules/jest-leak-detector": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz",
- "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.0.5.tgz",
+ "integrity": "sha512-3Uxr5uP8jmHMcsOtYMRB/zf1gXN3yUIc+iPorhNETG54gErFIiUhLvyY/OggYpSMOEYqsmRxmuU4ZOoX5jpRFg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "jest-get-type": "^29.6.3",
- "pretty-format": "^29.7.0"
+ "@jest/get-type": "30.0.1",
+ "pretty-format": "30.0.5"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-matcher-utils": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz",
- "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.0.5.tgz",
+ "integrity": "sha512-uQgGWt7GOrRLP1P7IwNWwK1WAQbq+m//ZY0yXygyfWp0rJlksMSLQAA4wYQC3b6wl3zfnchyTx+k3HZ5aPtCbQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "chalk": "^4.0.0",
- "jest-diff": "^29.7.0",
- "jest-get-type": "^29.6.3",
- "pretty-format": "^29.7.0"
+ "@jest/get-type": "30.0.1",
+ "chalk": "^4.1.2",
+ "jest-diff": "30.0.5",
+ "pretty-format": "30.0.5"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-message-util": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz",
- "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.0.5.tgz",
+ "integrity": "sha512-NAiDOhsK3V7RU0Aa/HnrQo+E4JlbarbmI3q6Pi4KcxicdtjV82gcIUrejOtczChtVQR4kddu1E1EJlW6EN9IyA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/code-frame": "^7.12.13",
- "@jest/types": "^29.6.3",
- "@types/stack-utils": "^2.0.0",
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.9",
- "micromatch": "^4.0.4",
- "pretty-format": "^29.7.0",
+ "@babel/code-frame": "^7.27.1",
+ "@jest/types": "30.0.5",
+ "@types/stack-utils": "^2.0.3",
+ "chalk": "^4.1.2",
+ "graceful-fs": "^4.2.11",
+ "micromatch": "^4.0.8",
+ "pretty-format": "30.0.5",
"slash": "^3.0.0",
- "stack-utils": "^2.0.3"
+ "stack-utils": "^2.0.6"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-mock": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz",
- "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.0.5.tgz",
+ "integrity": "sha512-Od7TyasAAQX/6S+QCbN6vZoWOMwlTtzzGuxJku1GhGanAjz9y+QsQkpScDmETvdc9aSXyJ/Op4rhpMYBWW91wQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/types": "^29.6.3",
+ "@jest/types": "30.0.5",
"@types/node": "*",
- "jest-util": "^29.7.0"
+ "jest-util": "30.0.5"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-pnp-resolver": {
@@ -7020,169 +6921,148 @@
}
},
"node_modules/jest-regex-util": {
- "version": "29.6.3",
- "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz",
- "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==",
+ "version": "30.0.1",
+ "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz",
+ "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==",
"dev": true,
"license": "MIT",
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-resolve": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz",
- "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.0.5.tgz",
+ "integrity": "sha512-d+DjBQ1tIhdz91B79mywH5yYu76bZuE96sSbxj8MkjWVx5WNdt1deEFRONVL4UkKLSrAbMkdhb24XN691yDRHg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.7.0",
- "jest-pnp-resolver": "^1.2.2",
- "jest-util": "^29.7.0",
- "jest-validate": "^29.7.0",
- "resolve": "^1.20.0",
- "resolve.exports": "^2.0.0",
- "slash": "^3.0.0"
+ "chalk": "^4.1.2",
+ "graceful-fs": "^4.2.11",
+ "jest-haste-map": "30.0.5",
+ "jest-pnp-resolver": "^1.2.3",
+ "jest-util": "30.0.5",
+ "jest-validate": "30.0.5",
+ "slash": "^3.0.0",
+ "unrs-resolver": "^1.7.11"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-resolve-dependencies": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz",
- "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.0.5.tgz",
+ "integrity": "sha512-/xMvBR4MpwkrHW4ikZIWRttBBRZgWK4d6xt3xW1iRDSKt4tXzYkMkyPfBnSCgv96cpkrctfXs6gexeqMYqdEpw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "jest-regex-util": "^29.6.3",
- "jest-snapshot": "^29.7.0"
+ "jest-regex-util": "30.0.1",
+ "jest-snapshot": "30.0.5"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-runner": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz",
- "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.0.5.tgz",
+ "integrity": "sha512-JcCOucZmgp+YuGgLAXHNy7ualBx4wYSgJVWrYMRBnb79j9PD0Jxh0EHvR5Cx/r0Ce+ZBC4hCdz2AzFFLl9hCiw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/console": "^29.7.0",
- "@jest/environment": "^29.7.0",
- "@jest/test-result": "^29.7.0",
- "@jest/transform": "^29.7.0",
- "@jest/types": "^29.6.3",
+ "@jest/console": "30.0.5",
+ "@jest/environment": "30.0.5",
+ "@jest/test-result": "30.0.5",
+ "@jest/transform": "30.0.5",
+ "@jest/types": "30.0.5",
"@types/node": "*",
- "chalk": "^4.0.0",
+ "chalk": "^4.1.2",
"emittery": "^0.13.1",
- "graceful-fs": "^4.2.9",
- "jest-docblock": "^29.7.0",
- "jest-environment-node": "^29.7.0",
- "jest-haste-map": "^29.7.0",
- "jest-leak-detector": "^29.7.0",
- "jest-message-util": "^29.7.0",
- "jest-resolve": "^29.7.0",
- "jest-runtime": "^29.7.0",
- "jest-util": "^29.7.0",
- "jest-watcher": "^29.7.0",
- "jest-worker": "^29.7.0",
+ "exit-x": "^0.2.2",
+ "graceful-fs": "^4.2.11",
+ "jest-docblock": "30.0.1",
+ "jest-environment-node": "30.0.5",
+ "jest-haste-map": "30.0.5",
+ "jest-leak-detector": "30.0.5",
+ "jest-message-util": "30.0.5",
+ "jest-resolve": "30.0.5",
+ "jest-runtime": "30.0.5",
+ "jest-util": "30.0.5",
+ "jest-watcher": "30.0.5",
+ "jest-worker": "30.0.5",
"p-limit": "^3.1.0",
"source-map-support": "0.5.13"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-runtime": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz",
- "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.0.5.tgz",
+ "integrity": "sha512-7oySNDkqpe4xpX5PPiJTe5vEa+Ak/NnNz2bGYZrA1ftG3RL3EFlHaUkA1Cjx+R8IhK0Vg43RML5mJedGTPNz3A==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/environment": "^29.7.0",
- "@jest/fake-timers": "^29.7.0",
- "@jest/globals": "^29.7.0",
- "@jest/source-map": "^29.6.3",
- "@jest/test-result": "^29.7.0",
- "@jest/transform": "^29.7.0",
- "@jest/types": "^29.6.3",
+ "@jest/environment": "30.0.5",
+ "@jest/fake-timers": "30.0.5",
+ "@jest/globals": "30.0.5",
+ "@jest/source-map": "30.0.1",
+ "@jest/test-result": "30.0.5",
+ "@jest/transform": "30.0.5",
+ "@jest/types": "30.0.5",
"@types/node": "*",
- "chalk": "^4.0.0",
- "cjs-module-lexer": "^1.0.0",
- "collect-v8-coverage": "^1.0.0",
- "glob": "^7.1.3",
- "graceful-fs": "^4.2.9",
- "jest-haste-map": "^29.7.0",
- "jest-message-util": "^29.7.0",
- "jest-mock": "^29.7.0",
- "jest-regex-util": "^29.6.3",
- "jest-resolve": "^29.7.0",
- "jest-snapshot": "^29.7.0",
- "jest-util": "^29.7.0",
+ "chalk": "^4.1.2",
+ "cjs-module-lexer": "^2.1.0",
+ "collect-v8-coverage": "^1.0.2",
+ "glob": "^10.3.10",
+ "graceful-fs": "^4.2.11",
+ "jest-haste-map": "30.0.5",
+ "jest-message-util": "30.0.5",
+ "jest-mock": "30.0.5",
+ "jest-regex-util": "30.0.1",
+ "jest-resolve": "30.0.5",
+ "jest-snapshot": "30.0.5",
+ "jest-util": "30.0.5",
"slash": "^3.0.0",
"strip-bom": "^4.0.0"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-runtime/node_modules/glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "deprecated": "Glob versions prior to v9 are no longer supported",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-snapshot": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz",
- "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@babel/core": "^7.11.6",
- "@babel/generator": "^7.7.2",
- "@babel/plugin-syntax-jsx": "^7.7.2",
- "@babel/plugin-syntax-typescript": "^7.7.2",
- "@babel/types": "^7.3.3",
- "@jest/expect-utils": "^29.7.0",
- "@jest/transform": "^29.7.0",
- "@jest/types": "^29.6.3",
- "babel-preset-current-node-syntax": "^1.0.0",
- "chalk": "^4.0.0",
- "expect": "^29.7.0",
- "graceful-fs": "^4.2.9",
- "jest-diff": "^29.7.0",
- "jest-get-type": "^29.6.3",
- "jest-matcher-utils": "^29.7.0",
- "jest-message-util": "^29.7.0",
- "jest-util": "^29.7.0",
- "natural-compare": "^1.4.0",
- "pretty-format": "^29.7.0",
- "semver": "^7.5.3"
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.0.5.tgz",
+ "integrity": "sha512-T00dWU/Ek3LqTp4+DcW6PraVxjk28WY5Ua/s+3zUKSERZSNyxTqhDXCWKG5p2HAJ+crVQ3WJ2P9YVHpj1tkW+g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.27.4",
+ "@babel/generator": "^7.27.5",
+ "@babel/plugin-syntax-jsx": "^7.27.1",
+ "@babel/plugin-syntax-typescript": "^7.27.1",
+ "@babel/types": "^7.27.3",
+ "@jest/expect-utils": "30.0.5",
+ "@jest/get-type": "30.0.1",
+ "@jest/snapshot-utils": "30.0.5",
+ "@jest/transform": "30.0.5",
+ "@jest/types": "30.0.5",
+ "babel-preset-current-node-syntax": "^1.1.0",
+ "chalk": "^4.1.2",
+ "expect": "30.0.5",
+ "graceful-fs": "^4.2.11",
+ "jest-diff": "30.0.5",
+ "jest-matcher-utils": "30.0.5",
+ "jest-message-util": "30.0.5",
+ "jest-util": "30.0.5",
+ "pretty-format": "30.0.5",
+ "semver": "^7.7.2",
+ "synckit": "^0.11.8"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-snapshot/node_modules/semver": {
@@ -7199,39 +7079,52 @@
}
},
"node_modules/jest-util": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz",
- "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.0.5.tgz",
+ "integrity": "sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/types": "^29.6.3",
+ "@jest/types": "30.0.5",
"@types/node": "*",
- "chalk": "^4.0.0",
- "ci-info": "^3.2.0",
- "graceful-fs": "^4.2.9",
- "picomatch": "^2.2.3"
+ "chalk": "^4.1.2",
+ "ci-info": "^4.2.0",
+ "graceful-fs": "^4.2.11",
+ "picomatch": "^4.0.2"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ }
+ },
+ "node_modules/jest-util/node_modules/picomatch": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/jest-validate": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz",
- "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.0.5.tgz",
+ "integrity": "sha512-ouTm6VFHaS2boyl+k4u+Qip4TSH7Uld5tyD8psQ8abGgt2uYYB8VwVfAHWHjHc0NWmGGbwO5h0sCPOGHHevefw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/types": "^29.6.3",
- "camelcase": "^6.2.0",
- "chalk": "^4.0.0",
- "jest-get-type": "^29.6.3",
+ "@jest/get-type": "30.0.1",
+ "@jest/types": "30.0.5",
+ "camelcase": "^6.3.0",
+ "chalk": "^4.1.2",
"leven": "^3.1.0",
- "pretty-format": "^29.7.0"
+ "pretty-format": "30.0.5"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-validate/node_modules/camelcase": {
@@ -7248,39 +7141,40 @@
}
},
"node_modules/jest-watcher": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz",
- "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.0.5.tgz",
+ "integrity": "sha512-z9slj/0vOwBDBjN3L4z4ZYaA+pG56d6p3kTUhFRYGvXbXMWhXmb/FIxREZCD06DYUwDKKnj2T80+Pb71CQ0KEg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/test-result": "^29.7.0",
- "@jest/types": "^29.6.3",
+ "@jest/test-result": "30.0.5",
+ "@jest/types": "30.0.5",
"@types/node": "*",
- "ansi-escapes": "^4.2.1",
- "chalk": "^4.0.0",
+ "ansi-escapes": "^4.3.2",
+ "chalk": "^4.1.2",
"emittery": "^0.13.1",
- "jest-util": "^29.7.0",
- "string-length": "^4.0.1"
+ "jest-util": "30.0.5",
+ "string-length": "^4.0.2"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-worker": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz",
- "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.0.5.tgz",
+ "integrity": "sha512-ojRXsWzEP16NdUuBw/4H/zkZdHOa7MMYCk4E430l+8fELeLg/mqmMlRhjL7UNZvQrDmnovWZV4DxX03fZF48fQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*",
- "jest-util": "^29.7.0",
+ "@ungap/structured-clone": "^1.3.0",
+ "jest-util": "30.0.5",
"merge-stream": "^2.0.0",
- "supports-color": "^8.0.0"
+ "supports-color": "^8.1.1"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/jest-worker/node_modules/supports-color": {
@@ -7409,16 +7303,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/kleur": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
- "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/leven": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
@@ -7755,9 +7639,9 @@
"license": "MIT"
},
"node_modules/napi-postinstall": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.2.tgz",
- "integrity": "sha512-tWVJxJHmBWLy69PvO96TZMZDrzmw5KeiZBz3RHmiM2XZ9grBJ2WgMAFVVg25nqp3ZjTFUs2Ftw1JhscL3Teliw==",
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.3.tgz",
+ "integrity": "sha512-uTp172LLXSxuSYHv/kou+f6KW3SMppU9ivthaVTXian9sOt3XM/zHYHpRZiLgQoxeWfYUnslNWQHF1+G71xcow==",
"dev": true,
"license": "MIT",
"bin": {
@@ -8504,18 +8388,18 @@
}
},
"node_modules/pretty-format": {
- "version": "29.7.0",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
- "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
+ "version": "30.0.5",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.0.5.tgz",
+ "integrity": "sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jest/schemas": "^29.6.3",
- "ansi-styles": "^5.0.0",
- "react-is": "^18.0.0"
+ "@jest/schemas": "30.0.5",
+ "ansi-styles": "^5.2.0",
+ "react-is": "^18.3.1"
},
"engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/pretty-format/node_modules/ansi-styles": {
@@ -8547,20 +8431,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/prompts": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
- "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "kleur": "^3.0.3",
- "sisteransi": "^1.0.5"
- },
- "engines": {
- "node": ">= 6"
- }
- },
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -8793,6 +8663,27 @@
"validate-npm-package-license": "^3.0.1"
}
},
+ "node_modules/read-pkg/node_modules/resolve": {
+ "version": "1.22.10",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
+ "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-core-module": "^2.16.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/read-pkg/node_modules/semver": {
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
@@ -8882,22 +8773,19 @@
}
},
"node_modules/resolve": {
- "version": "1.22.10",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
- "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
+ "version": "2.0.0-next.5",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
+ "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "is-core-module": "^2.16.0",
+ "is-core-module": "^2.13.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
},
"bin": {
"resolve": "bin/resolve"
},
- "engines": {
- "node": ">= 0.4"
- },
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@@ -8945,16 +8833,6 @@
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
}
},
- "node_modules/resolve.exports": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz",
- "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/reusify": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
@@ -9046,13 +8924,12 @@
}
},
"node_modules/selfsigned": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz",
- "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==",
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-3.0.1.tgz",
+ "integrity": "sha512-6U6w6kSLrM9Zxo0D7mC7QdGS6ZZytMWBnj/vhF9p+dAHx6CwGezuRcO4VclTbrrI7mg7SD6zNiqXUuBHOVopNQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@types/node-forge": "^1.3.0",
"node-forge": "^1"
},
"engines": {
@@ -9230,13 +9107,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/sisteransi": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
- "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
@@ -9298,9 +9168,9 @@
}
},
"node_modules/spdx-license-ids": {
- "version": "3.0.21",
- "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz",
- "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==",
+ "version": "3.0.22",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz",
+ "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==",
"dev": true,
"license": "CC0-1.0"
},
@@ -9693,6 +9563,22 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/synckit": {
+ "version": "0.11.11",
+ "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz",
+ "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@pkgr/core": "^0.2.9"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/synckit"
+ }
+ },
"node_modules/tapable": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz",
@@ -9762,11 +9648,14 @@
}
},
"node_modules/tinyglobby/node_modules/fdir": {
- "version": "6.4.6",
- "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
- "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"dev": true,
"license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
"peerDependencies": {
"picomatch": "^3 || ^4"
},
@@ -9869,13 +9758,13 @@
}
},
"node_modules/tsd": {
- "version": "0.32.0",
- "resolved": "https://registry.npmjs.org/tsd/-/tsd-0.32.0.tgz",
- "integrity": "sha512-R5lBZCbxGBowOcW0gpQaiIjGYrG5NmU+PfFDKcc3zbtzWjML1o/zAwzdDnS2ZheSlPu9GW51azpFqEPUBq9DoQ==",
+ "version": "0.33.0",
+ "resolved": "https://registry.npmjs.org/tsd/-/tsd-0.33.0.tgz",
+ "integrity": "sha512-/PQtykJFVw90QICG7zyPDMIyueOXKL7jOJVoX5pILnb3Ux+7QqynOxfVvarE+K+yi7BZyOSY4r+OZNWSWRiEwQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@tsd/typescript": "~5.8.3",
+ "@tsd/typescript": "^5.9.2",
"eslint-formatter-pretty": "^4.1.0",
"globby": "^11.0.1",
"jest-diff": "^29.0.3",
@@ -9890,6 +9779,55 @@
"node": ">=14.16"
}
},
+ "node_modules/tsd/node_modules/@jest/schemas": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
+ "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@sinclair/typebox": "^0.27.8"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/tsd/node_modules/@sinclair/typebox": {
+ "version": "0.27.8",
+ "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
+ "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tsd/node_modules/ansi-styles": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/tsd/node_modules/jest-diff": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz",
+ "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^4.0.0",
+ "diff-sequences": "^29.6.3",
+ "jest-get-type": "^29.6.3",
+ "pretty-format": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
"node_modules/tsd/node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -9900,6 +9838,21 @@
"node": ">=8"
}
},
+ "node_modules/tsd/node_modules/pretty-format": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
+ "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/schemas": "^29.6.3",
+ "ansi-styles": "^5.0.0",
+ "react-is": "^18.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
@@ -10033,9 +9986,9 @@
}
},
"node_modules/typescript": {
- "version": "5.8.3",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
- "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
+ "version": "5.9.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
+ "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -10047,16 +10000,16 @@
}
},
"node_modules/typescript-eslint": {
- "version": "8.38.0",
- "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.38.0.tgz",
- "integrity": "sha512-FsZlrYK6bPDGoLeZRuvx2v6qrM03I0U0SnfCLPs/XCCPCFD80xU9Pg09H/K+XFa68uJuZo7l/Xhs+eDRg2l3hg==",
+ "version": "8.39.1",
+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.39.1.tgz",
+ "integrity": "sha512-GDUv6/NDYngUlNvwaHM1RamYftxf782IyEDbdj3SeaIHHv8fNQVRC++fITT7kUJV/5rIA/tkoRSSskt6osEfqg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/eslint-plugin": "8.38.0",
- "@typescript-eslint/parser": "8.38.0",
- "@typescript-eslint/typescript-estree": "8.38.0",
- "@typescript-eslint/utils": "8.38.0"
+ "@typescript-eslint/eslint-plugin": "8.39.1",
+ "@typescript-eslint/parser": "8.39.1",
+ "@typescript-eslint/typescript-estree": "8.39.1",
+ "@typescript-eslint/utils": "8.39.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -10067,7 +10020,7 @@
},
"peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0",
- "typescript": ">=4.8.4 <5.9.0"
+ "typescript": ">=4.8.4 <6.0.0"
}
},
"node_modules/unbox-primitive": {
@@ -10462,26 +10415,19 @@
"license": "ISC"
},
"node_modules/write-file-atomic": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz",
- "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz",
+ "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==",
"dev": true,
"license": "ISC",
"dependencies": {
"imurmurhash": "^0.1.4",
- "signal-exit": "^3.0.7"
+ "signal-exit": "^4.0.1"
},
"engines": {
- "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
}
},
- "node_modules/write-file-atomic/node_modules/signal-exit": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
- "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
- "dev": true,
- "license": "ISC"
- },
"node_modules/ws": {
"version": "8.18.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
@@ -10522,9 +10468,9 @@
"license": "ISC"
},
"node_modules/yaml": {
- "version": "2.8.0",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz",
- "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==",
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz",
+ "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==",
"dev": true,
"license": "ISC",
"bin": {
diff --git a/deps/undici/src/package.json b/deps/undici/src/package.json
index 48948be80dd166..ef6fe2b902d370 100644
--- a/deps/undici/src/package.json
+++ b/deps/undici/src/package.json
@@ -1,6 +1,6 @@
{
"name": "undici",
- "version": "7.13.0",
+ "version": "7.14.0",
"description": "An HTTP/1.1 client, written from scratch for Node.js",
"homepage": "https://undici.nodejs.org",
"bugs": {
@@ -109,23 +109,23 @@
"devDependencies": {
"@fastify/busboy": "3.1.1",
"@matteo.collina/tspl": "^0.2.0",
+ "@metcoder95/https-pem": "^1.0.0",
"@sinonjs/fake-timers": "^12.0.0",
"@types/node": "^18.19.50",
"abort-controller": "^3.0.0",
"borp": "^0.20.0",
"c8": "^10.0.0",
- "cross-env": "^7.0.3",
+ "cross-env": "^10.0.0",
"dns-packet": "^5.4.0",
"esbuild": "^0.25.2",
"eslint": "^9.9.0",
"fast-check": "^4.1.1",
- "https-pem": "^3.0.0",
"husky": "^9.0.7",
- "jest": "^29.0.2",
+ "jest": "^30.0.5",
"neostandard": "^0.12.0",
"node-forge": "^1.3.1",
"proxy": "^2.1.1",
- "tsd": "^0.32.0",
+ "tsd": "^0.33.0",
"typescript": "^5.6.2",
"ws": "^8.11.0"
},
diff --git a/deps/undici/src/scripts/generate-pem.js b/deps/undici/src/scripts/generate-pem.js
index 88ac5c8392f610..7401b03733b893 100644
--- a/deps/undici/src/scripts/generate-pem.js
+++ b/deps/undici/src/scripts/generate-pem.js
@@ -1,4 +1,4 @@
'use strict'
/* istanbul ignore file */
-require('https-pem/install')
+require('@metcoder95/https-pem/install')
diff --git a/deps/undici/src/types/eventsource.d.ts b/deps/undici/src/types/eventsource.d.ts
index c85c4a14e586e4..081ca09aee97ff 100644
--- a/deps/undici/src/types/eventsource.d.ts
+++ b/deps/undici/src/types/eventsource.d.ts
@@ -56,6 +56,11 @@ export declare const EventSource: {
}
interface EventSourceInit {
- withCredentials?: boolean,
+ withCredentials?: boolean
+ // @deprecated use `node.dispatcher` instead
dispatcher?: Dispatcher
+ node?: {
+ dispatcher?: Dispatcher
+ reconnectionTime?: number
+ }
}
diff --git a/deps/undici/src/types/index.d.ts b/deps/undici/src/types/index.d.ts
index f9035293a95037..be0bc289c5f48c 100644
--- a/deps/undici/src/types/index.d.ts
+++ b/deps/undici/src/types/index.d.ts
@@ -34,7 +34,9 @@ export * from './content-type'
export * from './cache'
export { Interceptable } from './mock-interceptor'
-export { Dispatcher, BalancedPool, Pool, Client, buildConnector, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, setGlobalOrigin, getGlobalOrigin, interceptors, MockClient, MockPool, MockAgent, SnapshotAgent, MockCallHistory, MockCallHistoryLog, mockErrors, ProxyAgent, EnvHttpProxyAgent, RedirectHandler, DecoratorHandler, RetryHandler, RetryAgent, H2CClient }
+declare function globalThisInstall (): void
+
+export { Dispatcher, BalancedPool, Pool, Client, buildConnector, errors, Agent, request, stream, pipeline, connect, upgrade, setGlobalDispatcher, getGlobalDispatcher, setGlobalOrigin, getGlobalOrigin, interceptors, MockClient, MockPool, MockAgent, SnapshotAgent, MockCallHistory, MockCallHistoryLog, mockErrors, ProxyAgent, EnvHttpProxyAgent, RedirectHandler, DecoratorHandler, RetryHandler, RetryAgent, H2CClient, globalThisInstall as install }
export default Undici
declare namespace Undici {
@@ -74,4 +76,5 @@ declare namespace Undici {
MemoryCacheStore: typeof import('./cache-interceptor').default.MemoryCacheStore,
SqliteCacheStore: typeof import('./cache-interceptor').default.SqliteCacheStore
}
+ const install: typeof globalThisInstall
}
diff --git a/deps/undici/undici.js b/deps/undici/undici.js
index 651a8cd6159569..39132374b7ac2e 100644
--- a/deps/undici/undici.js
+++ b/deps/undici/undici.js
@@ -5477,7 +5477,7 @@ var require_formdata = __commonJS({
__name(this, "FormData");
}
#state = [];
- constructor(form) {
+ constructor(form = void 0) {
webidl.util.markAsUncloneable(this);
if (form !== void 0) {
throw webidl.errors.conversionFailed({
@@ -8782,7 +8782,6 @@ var require_proxy_agent = __commonJS({
"lib/dispatcher/proxy-agent.js"(exports2, module2) {
"use strict";
var { kProxy, kClose, kDestroy, kDispatch } = require_symbols();
- var { URL: URL2 } = require("node:url");
var Agent = require_agent();
var Pool = require_pool();
var DispatcherBase = require_dispatcher_base();
@@ -8848,7 +8847,7 @@ var require_proxy_agent = __commonJS({
} = opts;
opts.path = origin + path;
if (!("host" in headers) && !("Host" in headers)) {
- const { host } = new URL2(origin);
+ const { host } = new URL(origin);
headers.host = host;
}
opts.headers = { ...this[kProxyHeaders], ...headers };
@@ -8866,7 +8865,7 @@ var require_proxy_agent = __commonJS({
__name(this, "ProxyAgent");
}
constructor(opts) {
- if (!opts || typeof opts === "object" && !(opts instanceof URL2) && !opts.uri) {
+ if (!opts || typeof opts === "object" && !(opts instanceof URL) && !opts.uri) {
throw new InvalidArgumentError("Proxy uri is mandatory");
}
const { clientFactory = defaultFactory } = opts;
@@ -8895,7 +8894,7 @@ var require_proxy_agent = __commonJS({
this[kConnectEndpoint] = buildConnector({ ...opts.requestTls });
const agentFactory = opts.factory || defaultAgentFactory;
const factory = /* @__PURE__ */ __name((origin2, options) => {
- const { protocol: protocol2 } = new URL2(origin2);
+ const { protocol: protocol2 } = new URL(origin2);
if (!this[kTunnelProxy] && protocol2 === "http:" && this[kProxy].protocol === "http:") {
return new Http1ProxyWrapper(this[kProxy].uri, {
headers: this[kProxyHeaders],
@@ -8956,7 +8955,7 @@ var require_proxy_agent = __commonJS({
const headers = buildHeaders(opts.headers);
throwIfProxyAuthIsSent(headers);
if (headers && !("host" in headers) && !("Host" in headers)) {
- const { host } = new URL2(opts.origin);
+ const { host } = new URL(opts.origin);
headers.host = host;
}
return this[kAgent].dispatch(
@@ -8968,16 +8967,16 @@ var require_proxy_agent = __commonJS({
);
}
/**
- * @param {import('../types/proxy-agent').ProxyAgent.Options | string | URL} opts
+ * @param {import('../../types/proxy-agent').ProxyAgent.Options | string | URL} opts
* @returns {URL}
*/
#getUrl(opts) {
if (typeof opts === "string") {
- return new URL2(opts);
- } else if (opts instanceof URL2) {
+ return new URL(opts);
+ } else if (opts instanceof URL) {
return opts;
} else {
- return new URL2(opts.uri);
+ return new URL(opts.uri);
}
}
async [kClose]() {
@@ -9642,7 +9641,7 @@ var require_response = __commonJS({
var { URLSerializer } = require_data_url();
var { kConstruct } = require_symbols();
var assert = require("node:assert");
- var { types } = require("node:util");
+ var { isArrayBuffer } = nodeUtil.types;
var textEncoder = new TextEncoder("utf-8");
var Response = class _Response {
static {
@@ -9769,6 +9768,9 @@ var require_response = __commonJS({
});
}
const clonedResponse = cloneResponse(this.#state);
+ if (this.#state.body?.stream) {
+ streamRegistry.register(this, new WeakRef(this.#state.body.stream));
+ }
return fromInnerResponse(clonedResponse, getHeadersGuard(this.#headers));
}
[nodeUtil.inspect.custom](depth, options) {
@@ -9853,7 +9855,6 @@ var require_response = __commonJS({
const newResponse = makeResponse({ ...response, body: null });
if (response.body != null) {
newResponse.body = cloneBody(response.body);
- streamRegistry.register(newResponse, new WeakRef(response.body.stream));
}
return newResponse;
}
@@ -9999,7 +10000,7 @@ var require_response = __commonJS({
if (webidl.is.Blob(V)) {
return V;
}
- if (ArrayBuffer.isView(V) || types.isArrayBuffer(V)) {
+ if (ArrayBuffer.isView(V) || isArrayBuffer(V)) {
return V;
}
if (webidl.is.FormData(V)) {
@@ -11632,7 +11633,7 @@ var require_fetch = __commonJS({
fetchParams.controller.terminate(e);
}
}, "processBodyError");
- requestBody = async function* () {
+ requestBody = (async function* () {
try {
for await (const bytes of request.body.stream) {
yield* processBodyChunk(bytes);
@@ -11641,7 +11642,7 @@ var require_fetch = __commonJS({
} catch (err) {
processBodyError(err);
}
- }();
+ })();
}
try {
const { body, status, statusText, headersList, socket } = await dispatch({ body: requestBody });
@@ -13147,6 +13148,7 @@ var require_sender = __commonJS({
var require_websocket = __commonJS({
"lib/web/websocket/websocket.js"(exports2, module2) {
"use strict";
+ var { isArrayBuffer } = require("node:util/types");
var { webidl } = require_webidl();
var { URLSerializer } = require_data_url();
var { environmentSettingsObject } = require_util2();
@@ -13166,7 +13168,6 @@ var require_websocket = __commonJS({
var { ByteParser } = require_receiver();
var { kEnumerableProperty } = require_util();
var { getGlobalDispatcher: getGlobalDispatcher2 } = require_global2();
- var { types } = require("node:util");
var { ErrorEvent: ErrorEvent2, CloseEvent: CloseEvent2, createFastMessageEvent: createFastMessageEvent2 } = require_events();
var { SendQueue } = require_sender();
var { WebsocketFrameSend } = require_frame();
@@ -13306,7 +13307,7 @@ var require_websocket = __commonJS({
this.#sendQueue.add(buffer, () => {
this.#bufferedAmount -= buffer.byteLength;
}, sendHints.text);
- } else if (types.isArrayBuffer(data)) {
+ } else if (isArrayBuffer(data)) {
this.#bufferedAmount += data.byteLength;
this.#sendQueue.add(data, () => {
this.#bufferedAmount -= data.byteLength;
@@ -13440,11 +13441,17 @@ var require_websocket = __commonJS({
}
fireEvent("open", this);
if (channels.open.hasSubscribers) {
+ const headers = response.headersList.entries;
channels.open.publish({
address: response.socket.address(),
protocol: this.#protocol,
extensions: this.#extensions,
- websocket: this
+ websocket: this,
+ handshakeResponse: {
+ status: response.status,
+ statusText: response.statusText,
+ headers
+ }
});
}
}
@@ -13611,7 +13618,7 @@ var require_websocket = __commonJS({
if (webidl.is.Blob(V)) {
return V;
}
- if (ArrayBuffer.isView(V) || types.isArrayBuffer(V)) {
+ if (ArrayBuffer.isView(V) || isArrayBuffer(V)) {
return V;
}
}
@@ -13951,10 +13958,10 @@ var require_eventsource = __commonJS({
}
url = webidl.converters.USVString(url);
eventSourceInitDict = webidl.converters.EventSourceInitDict(eventSourceInitDict, prefix, "eventSourceInitDict");
- this.#dispatcher = eventSourceInitDict.dispatcher;
+ this.#dispatcher = eventSourceInitDict.node.dispatcher || eventSourceInitDict.dispatcher;
this.#state = {
lastEventId: "",
- reconnectionTime: defaultReconnectionTime
+ reconnectionTime: eventSourceInitDict.node.reconnectionTime
};
const settings = environmentSettingsObject;
let urlRecord;
@@ -14180,6 +14187,22 @@ var require_eventsource = __commonJS({
key: "dispatcher",
// undici only
converter: webidl.converters.any
+ },
+ {
+ key: "node",
+ // undici only
+ converter: webidl.dictionaryConverter([
+ {
+ key: "reconnectionTime",
+ converter: webidl.converters["unsigned long"],
+ defaultValue: /* @__PURE__ */ __name(() => defaultReconnectionTime, "defaultValue")
+ },
+ {
+ key: "dispatcher",
+ converter: webidl.converters.any
+ }
+ ]),
+ defaultValue: /* @__PURE__ */ __name(() => ({}), "defaultValue")
}
]);
module2.exports = {
diff --git a/deps/v8/src/heap/base/asm/s390/push_registers_asm.cc b/deps/v8/src/heap/base/asm/s390/push_registers_asm.cc
index ef954fa03ae8f2..80b6cf0664d627 100644
--- a/deps/v8/src/heap/base/asm/s390/push_registers_asm.cc
+++ b/deps/v8/src/heap/base/asm/s390/push_registers_asm.cc
@@ -21,17 +21,17 @@ asm(".text \n"
"PushAllRegistersAndIterateStack: \n"
// Push all callee-saved registers.
// r6-r13, r14 and sp(r15)
- " stmg %r6, %sp, 48(%sp) \n"
+ " stmg %r6, %r15, 48(%r15) \n"
// Allocate frame.
- " lay %sp, -160(%sp) \n"
+ " lay %r15, -160(%r15) \n"
// Pass 1st parameter (r2) unchanged (Stack*).
// Pass 2nd parameter (r3) unchanged (StackVisitor*).
// Save 3rd parameter (r4; IterateStackCallback).
" lgr %r5, %r4 \n"
// Pass sp as 3rd parameter. 160+48 to point
// to callee saved region stored above.
- " lay %r4, 208(%sp) \n"
+ " lay %r4, 208(%r15) \n"
// Call the callback.
" basr %r14, %r5 \n"
- " lmg %r14,%sp, 272(%sp) \n"
+ " lmg %r14,%r15, 272(%r15) \n"
" br %r14 \n");
diff --git a/deps/v8/src/wasm/baseline/ppc/liftoff-assembler-ppc-inl.h b/deps/v8/src/wasm/baseline/ppc/liftoff-assembler-ppc-inl.h
index 7ab51af2be9e68..2256229f868c56 100644
--- a/deps/v8/src/wasm/baseline/ppc/liftoff-assembler-ppc-inl.h
+++ b/deps/v8/src/wasm/baseline/ppc/liftoff-assembler-ppc-inl.h
@@ -2893,14 +2893,38 @@ void LiftoffAssembler::CallC(const std::initializer_list args,
parallel_move.LoadIntoRegister(LiftoffRegister{kCArgRegs[reg_args]}, arg);
++reg_args;
} else {
- int bias = 0;
- // On BE machines values with less than 8 bytes are right justified.
- // bias here is relative to the stack pointer.
- if (arg.kind() == kI32 || arg.kind() == kF32) bias = -stack_bias;
int offset =
(kStackFrameExtraParamSlot + stack_args) * kSystemPointerSize;
- MemOperand dst{sp, offset + bias};
- liftoff::StoreToMemory(this, dst, arg, r0, ip);
+ MemOperand dst{sp, offset};
+ Register scratch1 = r0;
+ Register scratch2 = ip;
+ if (arg.is_reg()) {
+ switch (arg.kind()) {
+ case kI16:
+ extsh(scratch1, arg.reg().gp());
+ StoreU64(scratch1, dst);
+ break;
+ case kI32:
+ extsw(scratch1, arg.reg().gp());
+ StoreU64(scratch1, dst);
+ break;
+ case kI64:
+ StoreU64(arg.reg().gp(), dst);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ } else if (arg.is_const()) {
+ mov(scratch1, Operand(static_cast(arg.i32_const())));
+ StoreU64(scratch1, dst);
+ } else if (value_kind_size(arg.kind()) == 4) {
+ LoadS32(scratch1, liftoff::GetStackSlot(arg.offset()), scratch2);
+ StoreU64(scratch1, dst);
+ } else {
+ DCHECK_EQ(8, value_kind_size(arg.kind()));
+ LoadU64(scratch1, liftoff::GetStackSlot(arg.offset()), scratch1);
+ StoreU64(scratch1, dst);
+ }
++stack_args;
}
}
diff --git a/deps/v8/src/wasm/baseline/s390/liftoff-assembler-s390-inl.h b/deps/v8/src/wasm/baseline/s390/liftoff-assembler-s390-inl.h
index bfd1eaf61e69f0..0be7b0e880a543 100644
--- a/deps/v8/src/wasm/baseline/s390/liftoff-assembler-s390-inl.h
+++ b/deps/v8/src/wasm/baseline/s390/liftoff-assembler-s390-inl.h
@@ -3271,14 +3271,37 @@ void LiftoffAssembler::CallC(const std::initializer_list args,
parallel_move.LoadIntoRegister(LiftoffRegister{kCArgRegs[reg_args]}, arg);
++reg_args;
} else {
- int bias = 0;
- // On BE machines values with less than 8 bytes are right justified.
- // bias here is relative to the stack pointer.
- if (arg.kind() == kI32 || arg.kind() == kF32) bias = -stack_bias;
int offset =
(kStackFrameExtraParamSlot + stack_args) * kSystemPointerSize;
- MemOperand dst{sp, offset + bias};
- liftoff::StoreToMemory(this, dst, arg, ip);
+ MemOperand dst{sp, offset};
+ Register scratch = ip;
+ if (arg.is_reg()) {
+ switch (arg.kind()) {
+ case kI16:
+ LoadS16(scratch, arg.reg().gp());
+ StoreU64(scratch, dst);
+ break;
+ case kI32:
+ LoadS32(scratch, arg.reg().gp());
+ StoreU64(scratch, dst);
+ break;
+ case kI64:
+ StoreU64(arg.reg().gp(), dst);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ } else if (arg.is_const()) {
+ mov(scratch, Operand(static_cast(arg.i32_const())));
+ StoreU64(scratch, dst);
+ } else if (value_kind_size(arg.kind()) == 4) {
+ LoadS32(scratch, liftoff::GetStackSlot(arg.offset()), scratch);
+ StoreU64(scratch, dst);
+ } else {
+ DCHECK_EQ(8, value_kind_size(arg.kind()));
+ LoadU64(scratch, liftoff::GetStackSlot(arg.offset()), scratch);
+ StoreU64(scratch, dst);
+ }
++stack_args;
}
}
diff --git a/doc/api/buffer.md b/doc/api/buffer.md
index c6c90b0bd29cce..70e32a6c998216 100644
--- a/doc/api/buffer.md
+++ b/doc/api/buffer.md
@@ -405,7 +405,7 @@ implementations. Specifically, the {TypedArray} variants accept a second
argument that is a mapping function that is invoked on every element of the
typed array:
-* `TypedArray.from(source[, mapFn[, thisArg]])`
+* [`TypedArray.from(source[, mapFn[, thisArg]])`][`TypedArray.from()`]
The `Buffer.from()` method, however, does not support the use of a mapping
function:
diff --git a/doc/api/cli.md b/doc/api/cli.md
index ba1356650c2383..01735cafddf762 100644
--- a/doc/api/cli.md
+++ b/doc/api/cli.md
@@ -2601,6 +2601,20 @@ changes:
The destination for the corresponding test reporter. See the documentation on
[test reporters][] for more details.
+### `--test-rerun-failures`
+
+
+
+A path to a file allowing the test runner to persist the state of the test
+suite between runs. The test runner will use this file to determine which tests
+have already succeeded or failed, allowing for re-running of failed tests
+without having to re-run the entire test suite. The test runner will create this
+file if it does not exist.
+See the documentation on [test reruns][] for more details.
+
### `--test-shard`
+
+> Stability: 1.2 - Release candidate
+
+* `algorithm` {string} Variant of Argon2, one of `"argon2d"`, `"argon2i"` or `"argon2id"`.
+* `parameters` {Object}
+ * `message` {string|ArrayBuffer|Buffer|TypedArray|DataView} REQUIRED, this is the password for password
+ hashing applications of Argon2.
+ * `nonce` {string|ArrayBuffer|Buffer|TypedArray|DataView} REQUIRED, must be at
+ least 8 bytes long. This is the salt for password hashing applications of Argon2.
+ * `parallelism` {number} REQUIRED, degree of parallelism determines how many computational chains (lanes)
+ can be run. Must be greater than 1 and less than `2**24-1`.
+ * `tagLength` {number} REQUIRED, the length of the key to generate. Must be greater than 4 and
+ less than `2**32-1`.
+ * `memory` {number} REQUIRED, memory cost in 1KiB blocks. Must be greater than
+ `8 * parallelism` and less than `2**32-1`. The actual number of blocks is rounded
+ down to the nearest multiple of `4 * parallelism`.
+ * `passes` {number} REQUIRED, number of passes (iterations). Must be greater than 1 and less
+ than `2**32-1`.
+ * `secret` {string|ArrayBuffer|Buffer|TypedArray|DataView|undefined} OPTIONAL, Random additional input,
+ similar to the salt, that should **NOT** be stored with the derived key. This is known as pepper in
+ password hashing applications. If used, must have a length not greater than `2**32-1` bytes.
+ * `associatedData` {string|ArrayBuffer|Buffer|TypedArray|DataView|undefined} OPTIONAL, Additional data to
+ be added to the hash, functionally equivalent to salt or secret, but meant for
+ non-random data. If used, must have a length not greater than `2**32-1` bytes.
+* `callback` {Function}
+ * `err` {Error}
+ * `derivedKey` {Buffer}
+
+Provides an asynchronous [Argon2][] implementation. Argon2 is a password-based
+key derivation function that is designed to be expensive computationally and
+memory-wise in order to make brute-force attacks unrewarding.
+
+The `nonce` should be as unique as possible. It is recommended that a nonce is
+random and at least 16 bytes long. See [NIST SP 800-132][] for details.
+
+When passing strings for `message`, `nonce`, `secret` or `associatedData`, please
+consider [caveats when using strings as inputs to cryptographic APIs][].
+
+The `callback` function is called with two arguments: `err` and `derivedKey`.
+`err` is an exception object when key derivation fails, otherwise `err` is
+`null`. `derivedKey` is passed to the callback as a [`Buffer`][].
+
+An exception is thrown when any of the input arguments specify invalid values
+or types.
+
+```mjs
+const { argon2, randomBytes } = await import('node:crypto');
+
+const parameters = {
+ message: 'password',
+ nonce: randomBytes(16),
+ parallelism: 4,
+ tagLength: 64,
+ memory: 65536,
+ passes: 3,
+};
+
+argon2('argon2id', parameters, (err, derivedKey) => {
+ if (err) throw err;
+ console.log(derivedKey.toString('hex')); // 'af91dad...9520f15'
+});
+```
+
+```cjs
+const { argon2, randomBytes } = require('node:crypto');
+
+const parameters = {
+ message: 'password',
+ nonce: randomBytes(16),
+ parallelism: 4,
+ tagLength: 64,
+ memory: 65536,
+ passes: 3,
+};
+
+argon2('argon2id', parameters, (err, derivedKey) => {
+ if (err) throw err;
+ console.log(derivedKey.toString('hex')); // 'af91dad...9520f15'
+});
+```
+
+### `crypto.argon2Sync(algorithm, parameters)`
+
+
+
+> Stability: 1.2 - Release candidate
+
+* `algorithm` {string} Variant of Argon2, one of `"argon2d"`, `"argon2i"` or `"argon2id"`.
+* `parameters` {Object}
+ * `message` {string|ArrayBuffer|Buffer|TypedArray|DataView} REQUIRED, this is the password for password
+ hashing applications of Argon2.
+ * `nonce` {string|ArrayBuffer|Buffer|TypedArray|DataView} REQUIRED, must be at
+ least 8 bytes long. This is the salt for password hashing applications of Argon2.
+ * `parallelism` {number} REQUIRED, degree of parallelism determines how many computational chains (lanes)
+ can be run. Must be greater than 1 and less than `2**24-1`.
+ * `tagLength` {number} REQUIRED, the length of the key to generate. Must be greater than 4 and
+ less than `2**32-1`.
+ * `memory` {number} REQUIRED, memory cost in 1KiB blocks. Must be greater than
+ `8 * parallelism` and less than `2**32-1`. The actual number of blocks is rounded
+ down to the nearest multiple of `4 * parallelism`.
+ * `passes` {number} REQUIRED, number of passes (iterations). Must be greater than 1 and less
+ than `2**32-1`.
+ * `secret` {string|ArrayBuffer|Buffer|TypedArray|DataView|undefined} OPTIONAL, Random additional input,
+ similar to the salt, that should **NOT** be stored with the derived key. This is known as pepper in
+ password hashing applications. If used, must have a length not greater than `2**32-1` bytes.
+ * `associatedData` {string|ArrayBuffer|Buffer|TypedArray|DataView|undefined} OPTIONAL, Additional data to
+ be added to the hash, functionally equivalent to salt or secret, but meant for
+ non-random data. If used, must have a length not greater than `2**32-1` bytes.
+* Returns: {Buffer}
+
+Provides a synchronous [Argon2][] implementation. Argon2 is a password-based
+key derivation function that is designed to be expensive computationally and
+memory-wise in order to make brute-force attacks unrewarding.
+
+The `nonce` should be as unique as possible. It is recommended that a nonce is
+random and at least 16 bytes long. See [NIST SP 800-132][] for details.
+
+When passing strings for `message`, `nonce`, `secret` or `associatedData`, please
+consider [caveats when using strings as inputs to cryptographic APIs][].
+
+An exception is thrown when key derivation fails, otherwise the derived key is
+returned as a [`Buffer`][].
+
+An exception is thrown when any of the input arguments specify invalid values
+or types.
+
+```mjs
+const { argon2Sync, randomBytes } = await import('node:crypto');
+
+const parameters = {
+ message: 'password',
+ nonce: randomBytes(16),
+ parallelism: 4,
+ tagLength: 64,
+ memory: 65536,
+ passes: 3,
+};
+
+const derivedKey = argon2Sync('argon2id', parameters);
+console.log(derivedKey.toString('hex')); // 'af91dad...9520f15'
+```
+
+```cjs
+const { argon2Sync, randomBytes } = require('node:crypto');
+
+const parameters = {
+ message: 'password',
+ nonce: randomBytes(16),
+ parallelism: 4,
+ tagLength: 64,
+ memory: 65536,
+ passes: 3,
+};
+
+const derivedKey = argon2Sync('argon2id', parameters);
+console.log(derivedKey.toString('hex')); // 'af91dad...9520f15'
+```
+
### `crypto.checkPrime(candidate[, options], callback)`
+
+> Stability: 1.2 - Release candidate
+
+* `key` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView|KeyObject} Private Key
+* `ciphertext` {ArrayBuffer|Buffer|TypedArray|DataView}
+* `callback` {Function}
+ * `err` {Error}
+ * `sharedKey` {Buffer}
+* Returns: {Buffer} if the `callback` function is not provided.
+
+
+
+Key decapsulation using a KEM algorithm with a private key.
+
+Supported key types and their KEM algorithms are:
+
+* `'rsa'`[^openssl30] RSA Secret Value Encapsulation
+* `'ec'`[^openssl32] DHKEM(P-256, HKDF-SHA256), DHKEM(P-384, HKDF-SHA256), DHKEM(P-521, HKDF-SHA256)
+* `'x25519'`[^openssl32] DHKEM(X25519, HKDF-SHA256)
+* `'x448'`[^openssl32] DHKEM(X448, HKDF-SHA512)
+* `'ml-kem-512'`[^openssl35] ML-KEM
+* `'ml-kem-768'`[^openssl35] ML-KEM
+* `'ml-kem-1024'`[^openssl35] ML-KEM
+
+If `key` is not a [`KeyObject`][], this function behaves as if `key` had been
+passed to [`crypto.createPrivateKey()`][].
+
+If the `callback` function is provided this function uses libuv's threadpool.
+
### `crypto.diffieHellman(options[, callback])`
+
+> Stability: 1.2 - Release candidate
+
+* `key` {Object|string|ArrayBuffer|Buffer|TypedArray|DataView|KeyObject} Public Key
+* `callback` {Function}
+ * `err` {Error}
+ * `result` {Object}
+ * `sharedKey` {Buffer}
+ * `ciphertext` {Buffer}
+* Returns: {Object} if the `callback` function is not provided.
+ * `sharedKey` {Buffer}
+ * `ciphertext` {Buffer}
+
+
+
+Key encapsulation using a KEM algorithm with a public key.
+
+Supported key types and their KEM algorithms are:
+
+* `'rsa'`[^openssl30] RSA Secret Value Encapsulation
+* `'ec'`[^openssl32] DHKEM(P-256, HKDF-SHA256), DHKEM(P-384, HKDF-SHA256), DHKEM(P-521, HKDF-SHA256)
+* `'x25519'`[^openssl32] DHKEM(X25519, HKDF-SHA256)
+* `'x448'`[^openssl32] DHKEM(X448, HKDF-SHA512)
+* `'ml-kem-512'`[^openssl35] ML-KEM
+* `'ml-kem-768'`[^openssl35] ML-KEM
+* `'ml-kem-1024'`[^openssl35] ML-KEM
+
+If `key` is not a [`KeyObject`][], this function behaves as if `key` had been
+passed to [`crypto.createPublicKey()`][].
If the `callback` function is provided this function uses libuv's threadpool.
@@ -3663,6 +3911,9 @@ underlying hash function. See [`crypto.createHmac()`][] for more information.
-* `type` {string} Must be `'rsa'`, `'rsa-pss'`, `'dsa'`, `'ec'`, `'ed25519'`,
- `'ed448'`, `'x25519'`, `'x448'`, `'dh'`, `'ml-dsa-44'`[^openssl35],
- `'ml-dsa-65'`[^openssl35], or `'ml-dsa-87'`[^openssl35].
+* `type` {string} The asymmetric key type to generate. See the
+ supported [asymmetric key types][].
* `options` {Object}
* `modulusLength` {number} Key size in bits (RSA, DSA).
* `publicExponent` {number} Public exponent (RSA). **Default:** `0x10001`.
@@ -3786,6 +4036,9 @@ a `Promise` for an `Object` with `publicKey` and `privateKey` properties.
-* `type` {string} Must be `'rsa'`, `'rsa-pss'`, `'dsa'`, `'ec'`, `'ed25519'`,
- `'ed448'`, `'x25519'`, `'x448'`, `'dh'`, `'ml-dsa-44'`[^openssl35],
- `'ml-dsa-65'`[^openssl35], or `'ml-dsa-87'`[^openssl35].
+* `type` {string} The asymmetric key type to generate. See the
+ supported [asymmetric key types][].
* `options` {Object}
* `modulusLength` {number} Key size in bits (RSA, DSA).
* `publicExponent` {number} Public exponent (RSA). **Default:** `0x10001`.
@@ -6185,6 +6437,10 @@ See the [list of SSL OP Flags][] for details.
|
+[^openssl30]: Requires OpenSSL >= 3.0
+
+[^openssl32]: Requires OpenSSL >= 3.2
+
[^openssl35]: Requires OpenSSL >= 3.5
[AEAD algorithms]: https://en.wikipedia.org/wiki/Authenticated_encryption
@@ -6268,6 +6524,8 @@ See the [list of SSL OP Flags][] for details.
[`verify.verify()`]: #verifyverifyobject-signature-signatureencoding
[`x509.fingerprint256`]: #x509fingerprint256
[`x509.verify(publicKey)`]: #x509verifypublickey
+[argon2]: https://www.rfc-editor.org/rfc/rfc9106.html
+[asymmetric key types]: #asymmetric-key-types
[caveats when using strings as inputs to cryptographic APIs]: #using-strings-as-inputs-to-cryptographic-apis
[certificate object]: tls.md#certificate-object
[encoding]: buffer.md#buffers-and-character-encodings
diff --git a/doc/api/environment_variables.md b/doc/api/environment_variables.md
index 4878eeaa9e6dcd..747d8313c4b7fa 100644
--- a/doc/api/environment_variables.md
+++ b/doc/api/environment_variables.md
@@ -96,10 +96,10 @@ For example:
MY_VAR_B = ' my variable b '
```
-will be treaded identically to:
+will be treated identically to:
```text
-MY_VAR_A = my variable
+MY_VAR_A = my variable a
MY_VAR_B = ' my variable b '
```
diff --git a/doc/api/errors.md b/doc/api/errors.md
index 17d7c6edcec2ab..86527156e57355 100644
--- a/doc/api/errors.md
+++ b/doc/api/errors.md
@@ -826,6 +826,12 @@ when an error occurs (and is caught) during the creation of the
context, for example, when the allocation fails or the maximum call stack
size is reached when the context is created.
+
+24.7.0
24.6.0
24.5.0
24.4.1
@@ -48,6 +49,218 @@
* [io.js](CHANGELOG_IOJS.md)
* [Archive](CHANGELOG_ARCHIVE.md)
+
+
+## 2025-08-27, Version 24.7.0 (Current), @targos
+
+### Notable Changes
+
+#### Post-Quantum Cryptography in `node:crypto`
+
+OpenSSL 3.5 on 24.x kicked off post-quantum cryptography efforts in Node.js by
+allowing use of NIST's post-quantum cryptography standards for future-proofing
+applications against quantum computing threats. The following post-quantum
+algorithms are now available in `node:crypto`:
+
+* ML-KEM (FIPS 203, Module-Lattice-Based Key-Encapsulation Mechanism Standard) through new `crypto.encapsulate()` and `crypto.decapsulate()` methods.
+* ML-DSA (FIPS 204, Module-Lattice-Based Digital Signature Standard) in the existing `crypto.sign()` and `crypto.verify()` methods.
+
+Contributed by Filip Skokan in [#59259](https://github.com/nodejs/node/pull/59259) and [#59491](https://github.com/nodejs/node/pull/59491).
+
+### Modern Algorithms in Web Cryptography API
+
+The second substantial [extension to the Web Cryptography API](https://wicg.github.io/webcrypto-modern-algos/)
+(`globalThis.crypto.subtle`) was recently accepted for incubation by WICG.
+The following algorithms and methods from this extension are now available in
+the Node.js Web Cryptography API implementation:
+
+* AES-OCB
+* ChaCha20-Poly1305
+* ML-DSA
+* ML-KEM
+* SHA-3
+* SHAKE
+* `subtle.getPublicKey()`
+* `SubtleCrypto.supports()`
+* ... with more coming in future releases.
+
+Contributed by Filip Skokan in [#59365](https://github.com/nodejs/node/pull/59365), [#59569](https://github.com/nodejs/node/pull/59569), [#59461](https://github.com/nodejs/node/pull/59461), and [#59539](https://github.com/nodejs/node/pull/59539).
+
+#### Node.js execution argument support in single executable applications
+
+The single executable application configuration now supports additional fields
+to specify Node.js execution arguments and control how they can be extended when
+the application is run.
+
+* `execArgv` takes an array of strings for the execution arguments to be used.
+* `execArgvExtension` takes one of the following values:
+ * `"none"`: No additional execution arguments are allowed.
+ * `"cli"`: Additional execution arguments can be provided via a special command-line flag `--node-options="--flag1 --flag2=value"` at run time.
+ * `"env"` (default): Additional execution arguments can be provided via the `NODE_OPTIONS` environment variable at run time.
+
+For example, with the following configuration:
+
+```json
+{
+ "main": "/path/to/bundled/script.js",
+ "output": "/path/to/write/the/generated/blob.blob",
+ "execArgv": ["--no-warnings"],
+ "execArgvExtension": "cli",
+}
+```
+
+If the generated single executable application is named `sea`, then running:
+
+```console
+sea --node-options="--max-old-space-size=4096" user-arg1 user-arg2
+```
+
+Would be equivalent to running:
+
+```console
+node --no-warnings --max-old-space-size=4096 /path/to/bundled/script.js user-arg1 user-arg2
+```
+
+Contributed by Joyee Cheung in [#59314](https://github.com/nodejs/node/pull/59314) and [#59560](https://github.com/nodejs/node/pull/59560).
+
+#### Root certificates updated to NSS 3.114
+
+Certificates added:
+
+* TrustAsia TLS ECC Root CA
+* TrustAsia TLS RSA Root CA
+* SwissSign RSA TLS Root CA 2022 - 1
+
+Certificates removed:
+
+* GlobalSign Root CA
+* Entrust.net Premium 2048 Secure Server CA
+* Baltimore CyberTrust Root
+* Comodo AAA Services root
+* XRamp Global CA Root
+* Go Daddy Class 2 CA
+* Starfield Class 2 CA
+
+#### Other Notable Changes
+
+* \[[`d3afc63c44`](https://github.com/nodejs/node/commit/d3afc63c44)] - **(SEMVER-MINOR)** **crypto**: add argon2() and argon2Sync() methods (Ranieri Althoff) [#50353](https://github.com/nodejs/node/pull/50353)
+* \[[`6ae202fcdf`](https://github.com/nodejs/node/commit/6ae202fcdf)] - **(SEMVER-MINOR)** **http**: add Agent.agentKeepAliveTimeoutBuffer option (Haram Jeong) [#59315](https://github.com/nodejs/node/pull/59315)
+* \[[`dafee05358`](https://github.com/nodejs/node/commit/dafee05358)] - **(SEMVER-MINOR)** **http2**: add support for raw header arrays in h2Stream.respond() (Tim Perry) [#59455](https://github.com/nodejs/node/pull/59455)
+* \[[`8dc6f5b696`](https://github.com/nodejs/node/commit/8dc6f5b696)] - **(SEMVER-MINOR)** **stream**: add brotli support to CompressionStream and DecompressionStream (Matthew Aitken) [#59464](https://github.com/nodejs/node/pull/59464)
+
+### Commits
+
+* \[[`0fa22cbf7c`](https://github.com/nodejs/node/commit/0fa22cbf7c)] - **benchmark**: calibrate config v8/serialize.js (Rafael Gonzaga) [#59586](https://github.com/nodejs/node/pull/59586)
+* \[[`f5ece45b45`](https://github.com/nodejs/node/commit/f5ece45b45)] - **benchmark**: reduce readfile-permission-enabled config (Rafael Gonzaga) [#59589](https://github.com/nodejs/node/pull/59589)
+* \[[`8ebd4f4434`](https://github.com/nodejs/node/commit/8ebd4f4434)] - **benchmark**: calibrate length of util.diff (Rafael Gonzaga) [#59588](https://github.com/nodejs/node/pull/59588)
+* \[[`7dee3ffd14`](https://github.com/nodejs/node/commit/7dee3ffd14)] - **benchmark**: reflect current OpenSSL in crypto key benchmarks (Filip Skokan) [#59459](https://github.com/nodejs/node/pull/59459)
+* \[[`027b861ca1`](https://github.com/nodejs/node/commit/027b861ca1)] - **benchmark, test**: replace CRLF variable with string literal (Lee Jiho) [#59466](https://github.com/nodejs/node/pull/59466)
+* \[[`89dd770889`](https://github.com/nodejs/node/commit/89dd770889)] - **build**: do not set `-mminimal-toc` with `clang` (Richard Lau) [#59484](https://github.com/nodejs/node/pull/59484)
+* \[[`e13de4542f`](https://github.com/nodejs/node/commit/e13de4542f)] - **child\_process**: remove unsafe array iteration (hotpineapple) [#59347](https://github.com/nodejs/node/pull/59347)
+* \[[`89fe63551e`](https://github.com/nodejs/node/commit/89fe63551e)] - **crypto**: load system CA certificates off thread (Joyee Cheung) [#59550](https://github.com/nodejs/node/pull/59550)
+* \[[`152c5ef518`](https://github.com/nodejs/node/commit/152c5ef518)] - **(SEMVER-MINOR)** **crypto**: add AES-OCB Web Cryptography algorithm (Filip Skokan) [#59539](https://github.com/nodejs/node/pull/59539)
+* \[[`c6c418343d`](https://github.com/nodejs/node/commit/c6c418343d)] - **crypto**: update root certificates to NSS 3.114 (Node.js GitHub Bot) [#59571](https://github.com/nodejs/node/pull/59571)
+* \[[`18a2ee5b6c`](https://github.com/nodejs/node/commit/18a2ee5b6c)] - **(SEMVER-MINOR)** **crypto**: support ML-KEM in Web Cryptography (Filip Skokan) [#59569](https://github.com/nodejs/node/pull/59569)
+* \[[`72937e5144`](https://github.com/nodejs/node/commit/72937e5144)] - **crypto**: require HMAC key length with SHA-3 hashes in Web Cryptography (Filip Skokan) [#59567](https://github.com/nodejs/node/pull/59567)
+* \[[`b7383186c7`](https://github.com/nodejs/node/commit/b7383186c7)] - **crypto**: fix subtle.getPublicKey error for secret type key inputs (Filip Skokan) [#59558](https://github.com/nodejs/node/pull/59558)
+* \[[`2d05c046db`](https://github.com/nodejs/node/commit/2d05c046db)] - **crypto**: return cached copies from CryptoKey algorithm and usages getters (Filip Skokan) [#59538](https://github.com/nodejs/node/pull/59538)
+* \[[`207ffbeb07`](https://github.com/nodejs/node/commit/207ffbeb07)] - **crypto**: use CryptoKey internal slots in Web Cryptography (Filip Skokan) [#59538](https://github.com/nodejs/node/pull/59538)
+* \[[`4276516781`](https://github.com/nodejs/node/commit/4276516781)] - **crypto**: normalize RsaHashedKeyParams publicExponent (Filip Skokan) [#59538](https://github.com/nodejs/node/pull/59538)
+* \[[`14741539a7`](https://github.com/nodejs/node/commit/14741539a7)] - **(SEMVER-MINOR)** **crypto**: support ML-KEM, DHKEM, and RSASVE key encapsulation mechanisms (Filip Skokan) [#59491](https://github.com/nodejs/node/pull/59491)
+* \[[`d3afc63c44`](https://github.com/nodejs/node/commit/d3afc63c44)] - **(SEMVER-MINOR)** **crypto**: add argon2() and argon2Sync() methods (Ranieri Althoff) [#50353](https://github.com/nodejs/node/pull/50353)
+* \[[`4fe383e45a`](https://github.com/nodejs/node/commit/4fe383e45a)] - **(SEMVER-MINOR)** **crypto**: support ML-DSA spki/pkcs8 key formats in Web Cryptography (Filip Skokan) [#59365](https://github.com/nodejs/node/pull/59365)
+* \[[`a95386fbf9`](https://github.com/nodejs/node/commit/a95386fbf9)] - **(SEMVER-MINOR)** **crypto**: subject some algorithms in Web Cryptography on BoringSSL absence (Filip Skokan) [#59365](https://github.com/nodejs/node/pull/59365)
+* \[[`3f47a2fb63`](https://github.com/nodejs/node/commit/3f47a2fb63)] - **(SEMVER-MINOR)** **crypto**: add ChaCha20-Poly1305 Web Cryptography algorithm (Filip Skokan) [#59365](https://github.com/nodejs/node/pull/59365)
+* \[[`6fcce9058a`](https://github.com/nodejs/node/commit/6fcce9058a)] - **(SEMVER-MINOR)** **crypto**: add subtle.getPublicKey() utility function in Web Cryptography (Filip Skokan) [#59365](https://github.com/nodejs/node/pull/59365)
+* \[[`76cde76429`](https://github.com/nodejs/node/commit/76cde76429)] - **(SEMVER-MINOR)** **crypto**: add SHA-3 Web Cryptography digest algorithms (Filip Skokan) [#59365](https://github.com/nodejs/node/pull/59365)
+* \[[`247d017501`](https://github.com/nodejs/node/commit/247d017501)] - **(SEMVER-MINOR)** **crypto**: add SHAKE Web Cryptography digest algorithms (Filip Skokan) [#59365](https://github.com/nodejs/node/pull/59365)
+* \[[`f4fbcca5ce`](https://github.com/nodejs/node/commit/f4fbcca5ce)] - **(SEMVER-MINOR)** **crypto**: add SubtleCrypto.supports feature detection in Web Cryptography (Filip Skokan) [#59365](https://github.com/nodejs/node/pull/59365)
+* \[[`a55382214f`](https://github.com/nodejs/node/commit/a55382214f)] - **(SEMVER-MINOR)** **crypto**: support ML-DSA in Web Cryptography (Filip Skokan) [#59365](https://github.com/nodejs/node/pull/59365)
+* \[[`c38988c860`](https://github.com/nodejs/node/commit/c38988c860)] - **crypto**: fix EVPKeyCtxPointer::publicCheck() (Tobias Nießen) [#59471](https://github.com/nodejs/node/pull/59471)
+* \[[`61c3bcdc56`](https://github.com/nodejs/node/commit/61c3bcdc56)] - **(SEMVER-MINOR)** **crypto**: support ML-KEM KeyObject (Filip Skokan) [#59461](https://github.com/nodejs/node/pull/59461)
+* \[[`0821b446fb`](https://github.com/nodejs/node/commit/0821b446fb)] - **deps**: update undici to 7.14.0 (Node.js GitHub Bot) [#59507](https://github.com/nodejs/node/pull/59507)
+* \[[`b3af17c065`](https://github.com/nodejs/node/commit/b3af17c065)] - **deps**: V8: cherry-pick 7b91e3e2cbaf (Milad Fa) [#59485](https://github.com/nodejs/node/pull/59485)
+* \[[`9b69baf146`](https://github.com/nodejs/node/commit/9b69baf146)] - **deps**: V8: cherry-pick 59d52e311bb1 (Milad Fa) [#59485](https://github.com/nodejs/node/pull/59485)
+* \[[`b4f202c2f1`](https://github.com/nodejs/node/commit/b4f202c2f1)] - **doc**: improve `sqlite.backup()` progress/fulfillment documentation (René) [#59598](https://github.com/nodejs/node/pull/59598)
+* \[[`40b217a2f9`](https://github.com/nodejs/node/commit/40b217a2f9)] - **doc**: clarify experimental platform vulnerability policy (Matteo Collina) [#59591](https://github.com/nodejs/node/pull/59591)
+* \[[`cf84fffea5`](https://github.com/nodejs/node/commit/cf84fffea5)] - **doc**: link to `TypedArray.from()` in signature (Aviv Keller) [#59226](https://github.com/nodejs/node/pull/59226)
+* \[[`4bf6ed0bf5`](https://github.com/nodejs/node/commit/4bf6ed0bf5)] - **doc**: fix typos in `environment_variables.md` (PhistucK) [#59536](https://github.com/nodejs/node/pull/59536)
+* \[[`1784c35a49`](https://github.com/nodejs/node/commit/1784c35a49)] - **doc**: add security incident reponse plan (Rafael Gonzaga) [#59470](https://github.com/nodejs/node/pull/59470)
+* \[[`b962560240`](https://github.com/nodejs/node/commit/b962560240)] - **doc**: clarify maxRSS unit in `process.resourceUsage()` (Alex Yang) [#59511](https://github.com/nodejs/node/pull/59511)
+* \[[`e6a6cdb9df`](https://github.com/nodejs/node/commit/e6a6cdb9df)] - **doc**: add missing Zstd strategy constants (RANDRIAMANANTENA Narindra Tiana Annaick) [#59312](https://github.com/nodejs/node/pull/59312)
+* \[[`a6a31cb467`](https://github.com/nodejs/node/commit/a6a31cb467)] - **(SEMVER-MINOR)** **doc**: compress Web Cryptography Algorithm matrix (Filip Skokan) [#59365](https://github.com/nodejs/node/pull/59365)
+* \[[`8f8960cfcb`](https://github.com/nodejs/node/commit/8f8960cfcb)] - **doc**: fix the version tls.DEFAULT\_CIPHERS was added (Allon Murienik) [#59247](https://github.com/nodejs/node/pull/59247)
+* \[[`9e76089f1a`](https://github.com/nodejs/node/commit/9e76089f1a)] - **doc**: clarify glob's exclude option behavior (hotpineapple) [#59245](https://github.com/nodejs/node/pull/59245)
+* \[[`dd5f835af7`](https://github.com/nodejs/node/commit/dd5f835af7)] - **doc**: add RafaelGSS as performance strategic lead (Rafael Gonzaga) [#59445](https://github.com/nodejs/node/pull/59445)
+* \[[`2b7a7a525e`](https://github.com/nodejs/node/commit/2b7a7a525e)] - **doc,crypto**: add supported asymmetric key types section (Filip Skokan) [#59492](https://github.com/nodejs/node/pull/59492)
+* \[[`2fafe4c3bb`](https://github.com/nodejs/node/commit/2fafe4c3bb)] - **esm**: link modules synchronously when no async loader hooks are used (Joyee Cheung) [#59519](https://github.com/nodejs/node/pull/59519)
+* \[[`5347c4997a`](https://github.com/nodejs/node/commit/5347c4997a)] - **esm**: show race error message for inner module job race (Joyee Cheung) [#59519](https://github.com/nodejs/node/pull/59519)
+* \[[`b56d8af2fe`](https://github.com/nodejs/node/commit/b56d8af2fe)] - **esm**: sync-ify module translation (Joyee Cheung) [#59453](https://github.com/nodejs/node/pull/59453)
+* \[[`b4a23d6a69`](https://github.com/nodejs/node/commit/b4a23d6a69)] - **http**: trim off brackets from IPv6 addresses with string operations (Krishnadas PC) [#59420](https://github.com/nodejs/node/pull/59420)
+* \[[`6ae202fcdf`](https://github.com/nodejs/node/commit/6ae202fcdf)] - **(SEMVER-MINOR)** **http**: add Agent.agentKeepAliveTimeoutBuffer option (Haram Jeong) [#59315](https://github.com/nodejs/node/pull/59315)
+* \[[`dafee05358`](https://github.com/nodejs/node/commit/dafee05358)] - **(SEMVER-MINOR)** **http2**: add support for raw header arrays in h2Stream.respond() (Tim Perry) [#59455](https://github.com/nodejs/node/pull/59455)
+* \[[`b7ea39d860`](https://github.com/nodejs/node/commit/b7ea39d860)] - **http2**: report sent headers object in client stream dcs (Darshan Sen) [#59419](https://github.com/nodejs/node/pull/59419)
+* \[[`ebe9272dae`](https://github.com/nodejs/node/commit/ebe9272dae)] - **inspector**: initial support websocket inspection (Shima Ryuhei) [#59404](https://github.com/nodejs/node/pull/59404)
+* \[[`b35041c7dc`](https://github.com/nodejs/node/commit/b35041c7dc)] - **inspector**: prevent propagation of promise hooks to noPromise hooks (Shima Ryuhei) [#58841](https://github.com/nodejs/node/pull/58841)
+* \[[`fe7176d7c6`](https://github.com/nodejs/node/commit/fe7176d7c6)] - **lib**: do not modify prototype deprecated asyncResource (encore) (Szymon Łągiewka) [#59518](https://github.com/nodejs/node/pull/59518)
+* \[[`93fc80a1e2`](https://github.com/nodejs/node/commit/93fc80a1e2)] - **(SEMVER-MINOR)** **lib**: refactor kSupportedAlgorithms (Filip Skokan) [#59365](https://github.com/nodejs/node/pull/59365)
+* \[[`9a12f71ad9`](https://github.com/nodejs/node/commit/9a12f71ad9)] - **lib**: simplify IPv6 checks in isLoopback() (Krishnadas) [#59375](https://github.com/nodejs/node/pull/59375)
+* \[[`566fb04c82`](https://github.com/nodejs/node/commit/566fb04c82)] - **meta**: update devcontainer to the latest schema (Aviv Keller) [#54347](https://github.com/nodejs/node/pull/54347)
+* \[[`389a24bbff`](https://github.com/nodejs/node/commit/389a24bbff)] - **module**: allow overriding linked requests for a ModuleWrap (Chengzhong Wu) [#59527](https://github.com/nodejs/node/pull/59527)
+* \[[`7880978fe3`](https://github.com/nodejs/node/commit/7880978fe3)] - **module**: correctly detect top-level await in ambiguous contexts (Shima Ryuhei) [#58646](https://github.com/nodejs/node/pull/58646)
+* \[[`99128d9244`](https://github.com/nodejs/node/commit/99128d9244)] - **node-api**: link to other programming language bindings (Chengzhong Wu) [#59516](https://github.com/nodejs/node/pull/59516)
+* \[[`65c870e6cb`](https://github.com/nodejs/node/commit/65c870e6cb)] - **node-api**: clarify enum value ABI stability (Chengzhong Wu) [#59085](https://github.com/nodejs/node/pull/59085)
+* \[[`352d63541a`](https://github.com/nodejs/node/commit/352d63541a)] - **sea**: implement execArgvExtension (Joyee Cheung) [#59560](https://github.com/nodejs/node/pull/59560)
+* \[[`c6e3d5d98d`](https://github.com/nodejs/node/commit/c6e3d5d98d)] - **(SEMVER-MINOR)** **sea**: support execArgv in sea config (Joyee Cheung) [#59314](https://github.com/nodejs/node/pull/59314)
+* \[[`e7084df4db`](https://github.com/nodejs/node/commit/e7084df4db)] - **sqlite**: add sqlite-type symbol for DatabaseSync (Alex Yang) [#59405](https://github.com/nodejs/node/pull/59405)
+* \[[`e2b6bdc640`](https://github.com/nodejs/node/commit/e2b6bdc640)] - **sqlite**: handle ?NNN parameters as positional (Edy Silva) [#59350](https://github.com/nodejs/node/pull/59350)
+* \[[`99e4a12731`](https://github.com/nodejs/node/commit/99e4a12731)] - **sqlite**: avoid useless call to FromMaybe() (Tobias Nießen) [#59490](https://github.com/nodejs/node/pull/59490)
+* \[[`dfd4962e5f`](https://github.com/nodejs/node/commit/dfd4962e5f)] - **src**: enforce assumptions in FIXED\_ONE\_BYTE\_STRING (Tobias Nießen) [#58155](https://github.com/nodejs/node/pull/58155)
+* \[[`93a368df04`](https://github.com/nodejs/node/commit/93a368df04)] - **src**: use simdjson to parse --snapshot-config (Joyee Cheung) [#59473](https://github.com/nodejs/node/pull/59473)
+* \[[`716750fcf8`](https://github.com/nodejs/node/commit/716750fcf8)] - **src**: fix order of CHECK\_NOT\_NULL/dereference (Tobias Nießen) [#59487](https://github.com/nodejs/node/pull/59487)
+* \[[`44a8ecf8d4`](https://github.com/nodejs/node/commit/44a8ecf8d4)] - **src**: assert memory calc for max-old-space-size-percentage (Asaf Federman) [#59460](https://github.com/nodejs/node/pull/59460)
+* \[[`3462b46fca`](https://github.com/nodejs/node/commit/3462b46fca)] - **src**: use simdjson::pad (0hm☘️) [#59391](https://github.com/nodejs/node/pull/59391)
+* \[[`3e1551d845`](https://github.com/nodejs/node/commit/3e1551d845)] - **src**: move shared\_ptr objects in KeyObjectData (Tobias Nießen) [#59472](https://github.com/nodejs/node/pull/59472)
+* \[[`c022c1f85a`](https://github.com/nodejs/node/commit/c022c1f85a)] - **src**: add internal GetOptionsAsFlags (Pietro Marchini) [#59138](https://github.com/nodejs/node/pull/59138)
+* \[[`c0f08454a3`](https://github.com/nodejs/node/commit/c0f08454a3)] - **src**: iterate metadata version entries with std::array (Chengzhong Wu) [#57866](https://github.com/nodejs/node/pull/57866)
+* \[[`f87836f3ae`](https://github.com/nodejs/node/commit/f87836f3ae)] - **src**: internalize `v8::ConvertableToTraceFormat` in traces (Chengzhong Wu) [#57866](https://github.com/nodejs/node/pull/57866)
+* \[[`852b8e46d8`](https://github.com/nodejs/node/commit/852b8e46d8)] - **src**: remove duplicate assignment of `O_EXCL` in node\_constants.cc (Daniel Osvaldo R) [#59049](https://github.com/nodejs/node/pull/59049)
+* \[[`64ffde608f`](https://github.com/nodejs/node/commit/64ffde608f)] - **src**: add Intel CET properties to large\_pages.S (tjuhaszrh) [#59363](https://github.com/nodejs/node/pull/59363)
+* \[[`823dce32ec`](https://github.com/nodejs/node/commit/823dce32ec)] - **src**: update OpenSSL pqc checks (Filip Skokan) [#59436](https://github.com/nodejs/node/pull/59436)
+* \[[`8dc6f5b696`](https://github.com/nodejs/node/commit/8dc6f5b696)] - **(SEMVER-MINOR)** **stream**: add brotli support to CompressionStream and DecompressionStream (Matthew Aitken) [#59464](https://github.com/nodejs/node/pull/59464)
+* \[[`b2b8383755`](https://github.com/nodejs/node/commit/b2b8383755)] - **test**: use mustSucceed in test-repl-tab-complete-import (Sohyeon Kim) [#59368](https://github.com/nodejs/node/pull/59368)
+* \[[`e3ad5cc2c6`](https://github.com/nodejs/node/commit/e3ad5cc2c6)] - **test**: skip sea tests on Linux ppc64le (Richard Lau) [#59563](https://github.com/nodejs/node/pull/59563)
+* \[[`f78f47ca5a`](https://github.com/nodejs/node/commit/f78f47ca5a)] - **test**: support standalone env comment in tests (Pietro Marchini) [#59546](https://github.com/nodejs/node/pull/59546)
+* \[[`0e8bc2c7ac`](https://github.com/nodejs/node/commit/0e8bc2c7ac)] - **test**: rename test-net-server-drop-connections-in-cluster.js to -http- (Meghan Denny) [#59532](https://github.com/nodejs/node/pull/59532)
+* \[[`ed339580af`](https://github.com/nodejs/node/commit/ed339580af)] - **test**: lazy-load internalTTy (Pietro Marchini) [#59517](https://github.com/nodejs/node/pull/59517)
+* \[[`fe86bc6da8`](https://github.com/nodejs/node/commit/fe86bc6da8)] - **test**: fix `test-setproctitle` status when `ps` is not available (Antoine du Hamel) [#59523](https://github.com/nodejs/node/pull/59523)
+* \[[`e517792973`](https://github.com/nodejs/node/commit/e517792973)] - **test**: add parseTestMetadata support (Pietro Marchini) [#59503](https://github.com/nodejs/node/pull/59503)
+* \[[`31092972d6`](https://github.com/nodejs/node/commit/31092972d6)] - **test**: update WPT for WebCryptoAPI to ff26d9b307 (Node.js GitHub Bot) [#59497](https://github.com/nodejs/node/pull/59497)
+* \[[`16afd103cc`](https://github.com/nodejs/node/commit/16afd103cc)] - **(SEMVER-MINOR)** **test**: add Web Cryptography wrap/unwrap vectors (Filip Skokan) [#59365](https://github.com/nodejs/node/pull/59365)
+* \[[`5598baf34e`](https://github.com/nodejs/node/commit/5598baf34e)] - **(SEMVER-MINOR)** **test**: cleanup test-webcrypto-supports (Filip Skokan) [#59365](https://github.com/nodejs/node/pull/59365)
+* \[[`e7809d6ddb`](https://github.com/nodejs/node/commit/e7809d6ddb)] - **test**: make test-debug-process locale-independent (BCD1me) [#59254](https://github.com/nodejs/node/pull/59254)
+* \[[`ca7856e73c`](https://github.com/nodejs/node/commit/ca7856e73c)] - **test**: mark test-wasi-pthread as flaky (Joyee Cheung) [#59488](https://github.com/nodejs/node/pull/59488)
+* \[[`0ecd82197f`](https://github.com/nodejs/node/commit/0ecd82197f)] - **test**: split test-wasi.js (Joyee Cheung) [#59488](https://github.com/nodejs/node/pull/59488)
+* \[[`0930c218d6`](https://github.com/nodejs/node/commit/0930c218d6)] - **test**: deflake connection refused proxy tests (Joyee Cheung) [#59476](https://github.com/nodejs/node/pull/59476)
+* \[[`7f457f886a`](https://github.com/nodejs/node/commit/7f457f886a)] - **test**: use case-insensitive path checking on Windows in fs.cpSync tests (Joyee Cheung) [#59475](https://github.com/nodejs/node/pull/59475)
+* \[[`37809115f9`](https://github.com/nodejs/node/commit/37809115f9)] - **test**: add missing hasPostData in test-inspector-emit-protocol-event (Shima Ryuhei) [#59412](https://github.com/nodejs/node/pull/59412)
+* \[[`f4722b1672`](https://github.com/nodejs/node/commit/f4722b1672)] - **test**: refactor error checks to use assert.ifError/mustSucceed (Sohyeon Kim) [#59424](https://github.com/nodejs/node/pull/59424)
+* \[[`9ff71a672d`](https://github.com/nodejs/node/commit/9ff71a672d)] - **test**: fix typos (Lee Jiho) [#59330](https://github.com/nodejs/node/pull/59330)
+* \[[`9a7700da62`](https://github.com/nodejs/node/commit/9a7700da62)] - **test**: skip test-watch-mode inspect when no inspector (James M Snell) [#59440](https://github.com/nodejs/node/pull/59440)
+* \[[`e964c4334e`](https://github.com/nodejs/node/commit/e964c4334e)] - **test\_runner**: do not error when getting `fullName` of root context (René) [#59377](https://github.com/nodejs/node/pull/59377)
+* \[[`e076f7857c`](https://github.com/nodejs/node/commit/e076f7857c)] - **test\_runner**: add option to rerun only failed tests (Moshe Atlow) [#59443](https://github.com/nodejs/node/pull/59443)
+* \[[`eb8b1939a4`](https://github.com/nodejs/node/commit/eb8b1939a4)] - **test\_runner**: fix isSkipped check in junit (Sungwon) [#59414](https://github.com/nodejs/node/pull/59414)
+* \[[`4e02ea1c52`](https://github.com/nodejs/node/commit/4e02ea1c52)] - **tools**: update gyp-next to 0.20.3 (Node.js GitHub Bot) [#59603](https://github.com/nodejs/node/pull/59603)
+* \[[`99da7fbe11`](https://github.com/nodejs/node/commit/99da7fbe11)] - **tools**: avoid parsing test files twice (Pietro Marchini) [#59526](https://github.com/nodejs/node/pull/59526)
+* \[[`9a6a8e319b`](https://github.com/nodejs/node/commit/9a6a8e319b)] - **tools**: update coverage GitHub Actions to fixed version (Rich Trott) [#59512](https://github.com/nodejs/node/pull/59512)
+* \[[`8d28236aff`](https://github.com/nodejs/node/commit/8d28236aff)] - **tools**: fix return value of try\_check\_compiler (theanarkh) [#59434](https://github.com/nodejs/node/pull/59434)
+* \[[`52ab64ec3a`](https://github.com/nodejs/node/commit/52ab64ec3a)] - **tools**: bump @eslint/plugin-kit from 0.3.3 to 0.3.4 in /tools/eslint (dependabot\[bot]) [#59271](https://github.com/nodejs/node/pull/59271)
+* \[[`baa22893bb`](https://github.com/nodejs/node/commit/baa22893bb)] - **typings**: add missing URLBinding methods (성우현 | Woohyun Sung) [#59468](https://github.com/nodejs/node/pull/59468)
+* \[[`b68e0d1eca`](https://github.com/nodejs/node/commit/b68e0d1eca)] - **util**: fix error's namespaced node\_modules highlighting using inspect (Ruben Bridgewater) [#59446](https://github.com/nodejs/node/pull/59446)
+* \[[`15ae21b88a`](https://github.com/nodejs/node/commit/15ae21b88a)] - **util**: add some additional error classes to `wellKnownPrototypes` (Mark S. Miller) [#59456](https://github.com/nodejs/node/pull/59456)
+* \[[`c38b7cfa35`](https://github.com/nodejs/node/commit/c38b7cfa35)] - **worker**: fix worker name with \0 (theanarkh) [#59214](https://github.com/nodejs/node/pull/59214)
+* \[[`f54ace694a`](https://github.com/nodejs/node/commit/f54ace694a)] - **worker**: add worker name to report (theanarkh) [#58935](https://github.com/nodejs/node/pull/58935)
+
## 2025-08-14, Version 24.6.0 (Current), @RafaelGSS
diff --git a/doc/contributing/strategic-initiatives.md b/doc/contributing/strategic-initiatives.md
index 0643b9254ea7ee..b148f7c95c8d10 100644
--- a/doc/contributing/strategic-initiatives.md
+++ b/doc/contributing/strategic-initiatives.md
@@ -14,7 +14,7 @@ agenda to ensure they are active and have the support they need.
| V8 Currency | [Michaël Zasso][targos] | |
| Next-10 | [Michael Dawson][mhdawson] | |
| Single executable apps | [Darshan Sen][RaisinTen] | |
-| Performance | | |
+| Performance | [Rafael Gonzaga][RafaelGSS] | |
| Primordials | [Benjamin Gruenbaum][benjamingr] | |
@@ -39,6 +39,7 @@ agenda to ensure they are active and have the support they need.
+[RafaelGSS]: https://github.com/RafaelGSS
[RaisinTen]: https://github.com/RaisinTen
[benjamingr]: https://github.com/benjamingr
[jasnell]: https://github.com/jasnell
diff --git a/doc/node-config-schema.json b/doc/node-config-schema.json
index ba83550f09426c..4340c95b952d2a 100644
--- a/doc/node-config-schema.json
+++ b/doc/node-config-schema.json
@@ -443,6 +443,9 @@
}
]
},
+ "test-rerun-failures": {
+ "type": "string"
+ },
"test-shard": {
"type": "string"
},
@@ -695,6 +698,9 @@
}
]
},
+ "test-rerun-failures": {
+ "type": "string"
+ },
"test-shard": {
"type": "string"
},
diff --git a/doc/node.1 b/doc/node.1
index 3e9b376a0739b2..6210cbf42b26d4 100644
--- a/doc/node.1
+++ b/doc/node.1
@@ -490,6 +490,10 @@ A test reporter to use when running tests.
.It Fl -test-reporter-destination
The destination for the corresponding test reporter.
.
+.It Fl -test-rerun-failures
+Configures the tests runner to persist the state of tests to allow
+rerunning only failed tests.
+.
.It Fl -test-only
Configures the test runner to only execute top level tests that have the `only`
option set.
diff --git a/lib/_http_agent.js b/lib/_http_agent.js
index ddb6cd7d9a4c03..28006353a35f34 100644
--- a/lib/_http_agent.js
+++ b/lib/_http_agent.js
@@ -22,6 +22,7 @@
'use strict';
const {
+ NumberIsFinite,
NumberParseInt,
ObjectKeys,
ObjectSetPrototypeOf,
@@ -60,8 +61,6 @@ const kOnKeylog = Symbol('onkeylog');
const kRequestOptions = Symbol('requestOptions');
const kRequestAsyncResource = Symbol('requestAsyncResource');
-// TODO(jazelly): make this configurable
-const HTTP_AGENT_KEEP_ALIVE_TIMEOUT_BUFFER = 1000;
// New Agent code.
// The largest departure from the previous implementation is that
@@ -114,6 +113,14 @@ function Agent(options) {
this.scheduling = this.options.scheduling || 'lifo';
this.maxTotalSockets = this.options.maxTotalSockets;
this.totalSocketCount = 0;
+
+ this.agentKeepAliveTimeoutBuffer =
+ typeof this.options.agentKeepAliveTimeoutBuffer === 'number' &&
+ this.options.agentKeepAliveTimeoutBuffer >= 0 &&
+ NumberIsFinite(this.options.agentKeepAliveTimeoutBuffer) ?
+ this.options.agentKeepAliveTimeoutBuffer :
+ 1000;
+
const proxyEnv = this.options.proxyEnv;
if (typeof proxyEnv === 'object' && proxyEnv !== null) {
this[kProxyConfig] = parseProxyConfigFromEnv(proxyEnv, this.protocol, this.keepAlive);
@@ -559,7 +566,7 @@ Agent.prototype.keepSocketAlive = function keepSocketAlive(socket) {
if (hint) {
// Let the timer expire before the announced timeout to reduce
// the likelihood of ECONNRESET errors
- let serverHintTimeout = (NumberParseInt(hint) * 1000) - HTTP_AGENT_KEEP_ALIVE_TIMEOUT_BUFFER;
+ let serverHintTimeout = (NumberParseInt(hint) * 1000) - this.agentKeepAliveTimeoutBuffer;
serverHintTimeout = serverHintTimeout > 0 ? serverHintTimeout : 0;
if (serverHintTimeout === 0) {
// Cannot safely reuse the socket because the server timeout is
diff --git a/lib/async_hooks.js b/lib/async_hooks.js
index 4216ee3f240c48..1eb00871e2ebe6 100644
--- a/lib/async_hooks.js
+++ b/lib/async_hooks.js
@@ -262,10 +262,10 @@ class AsyncResource {
enumerable: true,
get: deprecate(function() {
return self;
- }, 'The asyncResource property on bound functions is deprecated', 'DEP0172', false),
+ }, 'The asyncResource property on bound functions is deprecated', 'DEP0172', false, false),
set: deprecate(function(val) {
self = val;
- }, 'The asyncResource property on bound functions is deprecated', 'DEP0172', false),
+ }, 'The asyncResource property on bound functions is deprecated', 'DEP0172', false, false),
},
});
return bound;
diff --git a/lib/child_process.js b/lib/child_process.js
index baa0a56d1ecdc7..17c6b69c118a75 100644
--- a/lib/child_process.js
+++ b/lib/child_process.js
@@ -648,7 +648,8 @@ function normalizeSpawnArguments(file, args, options) {
'DEP0190');
emittedDEP0190Already = true;
}
- const command = ArrayPrototypeJoin([file, ...args], ' ');
+
+ const command = args.length > 0 ? `${file} ${ArrayPrototypeJoin(args, ' ')}` : file;
// Set the shell, switches, and commands.
if (process.platform === 'win32') {
if (typeof options.shell === 'string')
diff --git a/lib/crypto.js b/lib/crypto.js
index 8e0c39f756a72b..4290989f3cd6b1 100644
--- a/lib/crypto.js
+++ b/lib/crypto.js
@@ -57,6 +57,10 @@ const {
randomInt,
randomUUID,
} = require('internal/crypto/random');
+const {
+ argon2,
+ argon2Sync,
+} = require('internal/crypto/argon2');
const {
pbkdf2,
pbkdf2Sync,
@@ -118,6 +122,10 @@ const {
secureHeapUsed,
} = require('internal/crypto/util');
const Certificate = require('internal/crypto/certificate');
+const {
+ encapsulate,
+ decapsulate,
+} = require('internal/crypto/kem');
let webcrypto;
function lazyWebCrypto() {
@@ -171,6 +179,8 @@ function createVerify(algorithm, options) {
module.exports = {
// Methods
+ argon2,
+ argon2Sync,
checkPrime,
checkPrimeSync,
createCipheriv,
@@ -219,6 +229,8 @@ module.exports = {
setFips,
verify: verifyOneShot,
hash,
+ encapsulate,
+ decapsulate,
// Classes
Certificate,
diff --git a/lib/inspector.js b/lib/inspector.js
index 4bf3ef7b61e99f..a6b835bbc7d529 100644
--- a/lib/inspector.js
+++ b/lib/inspector.js
@@ -219,6 +219,10 @@ const Network = {
loadingFailed: (params) => broadcastToFrontend('Network.loadingFailed', params),
dataSent: (params) => broadcastToFrontend('Network.dataSent', params),
dataReceived: (params) => broadcastToFrontend('Network.dataReceived', params),
+ webSocketCreated: (params) => broadcastToFrontend('Network.webSocketCreated', params),
+ webSocketClosed: (params) => broadcastToFrontend('Network.webSocketClosed', params),
+ webSocketHandshakeResponseReceived:
+ (params) => broadcastToFrontend('Network.webSocketHandshakeResponseReceived', params),
};
const NetworkResources = {
diff --git a/lib/internal/async_hooks.js b/lib/internal/async_hooks.js
index f4a45c99858c55..5f28ea6a0e8193 100644
--- a/lib/internal/async_hooks.js
+++ b/lib/internal/async_hooks.js
@@ -189,7 +189,7 @@ function lookupPublicResource(resource) {
// Used by C++ to call all init() callbacks. Because some state can be setup
// from C++ there's no need to perform all the same operations as in
// emitInitScript.
-function emitInitNative(asyncId, type, triggerAsyncId, resource) {
+function emitInitNative(asyncId, type, triggerAsyncId, resource, isPromiseHook) {
active_hooks.call_depth += 1;
resource = lookupPublicResource(resource);
// Use a single try/catch for all hooks to avoid setting up one per iteration.
@@ -199,6 +199,10 @@ function emitInitNative(asyncId, type, triggerAsyncId, resource) {
// eslint-disable-next-line no-var
for (var i = 0; i < active_hooks.array.length; i++) {
if (typeof active_hooks.array[i][init_symbol] === 'function') {
+ if (isPromiseHook &&
+ active_hooks.array[i][kNoPromiseHook]) {
+ continue;
+ }
active_hooks.array[i][init_symbol](
asyncId, type, triggerAsyncId,
resource,
@@ -222,7 +226,7 @@ function emitInitNative(asyncId, type, triggerAsyncId, resource) {
// Called from native. The asyncId stack handling is taken care of there
// before this is called.
-function emitHook(symbol, asyncId) {
+function emitHook(symbol, asyncId, isPromiseHook) {
active_hooks.call_depth += 1;
// Use a single try/catch for all hook to avoid setting up one per
// iteration.
@@ -232,6 +236,10 @@ function emitHook(symbol, asyncId) {
// eslint-disable-next-line no-var
for (var i = 0; i < active_hooks.array.length; i++) {
if (typeof active_hooks.array[i][symbol] === 'function') {
+ if (isPromiseHook &&
+ active_hooks.array[i][kNoPromiseHook]) {
+ continue;
+ }
active_hooks.array[i][symbol](asyncId);
}
}
@@ -321,7 +329,7 @@ function promiseInitHook(promise, parent) {
trackPromise(promise, parent);
const asyncId = promise[async_id_symbol];
const triggerAsyncId = promise[trigger_async_id_symbol];
- emitInitScript(asyncId, 'PROMISE', triggerAsyncId, promise);
+ emitInitScript(asyncId, 'PROMISE', triggerAsyncId, promise, true);
}
function promiseInitHookWithDestroyTracking(promise, parent) {
@@ -339,14 +347,14 @@ function promiseBeforeHook(promise) {
trackPromise(promise);
const asyncId = promise[async_id_symbol];
const triggerId = promise[trigger_async_id_symbol];
- emitBeforeScript(asyncId, triggerId, promise);
+ emitBeforeScript(asyncId, triggerId, promise, true);
}
function promiseAfterHook(promise) {
trackPromise(promise);
const asyncId = promise[async_id_symbol];
if (hasHooks(kAfter)) {
- emitAfterNative(asyncId);
+ emitAfterNative(asyncId, true);
}
if (asyncId === executionAsyncId()) {
// This condition might not be true if async_hooks was enabled during
@@ -361,7 +369,7 @@ function promiseAfterHook(promise) {
function promiseResolveHook(promise) {
trackPromise(promise);
const asyncId = promise[async_id_symbol];
- emitPromiseResolveNative(asyncId);
+ emitPromiseResolveNative(asyncId, true);
}
let wantPromiseHook = false;
@@ -492,7 +500,7 @@ function promiseResolveHooksExist() {
}
-function emitInitScript(asyncId, type, triggerAsyncId, resource) {
+function emitInitScript(asyncId, type, triggerAsyncId, resource, isPromiseHook = false) {
// Short circuit all checks for the common case. Which is that no hooks have
// been set. Do this to remove performance impact for embedders (and core).
if (!hasHooks(kInit))
@@ -502,15 +510,15 @@ function emitInitScript(asyncId, type, triggerAsyncId, resource) {
triggerAsyncId = getDefaultTriggerAsyncId();
}
- emitInitNative(asyncId, type, triggerAsyncId, resource);
+ emitInitNative(asyncId, type, triggerAsyncId, resource, isPromiseHook);
}
-function emitBeforeScript(asyncId, triggerAsyncId, resource) {
+function emitBeforeScript(asyncId, triggerAsyncId, resource, isPromiseHook = false) {
pushAsyncContext(asyncId, triggerAsyncId, resource);
if (hasHooks(kBefore))
- emitBeforeNative(asyncId);
+ emitBeforeNative(asyncId, isPromiseHook);
}
diff --git a/lib/internal/crypto/aes.js b/lib/internal/crypto/aes.js
index b7d1abf4a85daf..0abffe85c9881b 100644
--- a/lib/internal/crypto/aes.js
+++ b/lib/internal/crypto/aes.js
@@ -18,14 +18,17 @@ const {
kKeyVariantAES_CBC_128,
kKeyVariantAES_GCM_128,
kKeyVariantAES_KW_128,
+ kKeyVariantAES_OCB_128,
kKeyVariantAES_CTR_192,
kKeyVariantAES_CBC_192,
kKeyVariantAES_GCM_192,
kKeyVariantAES_KW_192,
+ kKeyVariantAES_OCB_192,
kKeyVariantAES_CTR_256,
kKeyVariantAES_CBC_256,
kKeyVariantAES_GCM_256,
kKeyVariantAES_KW_256,
+ kKeyVariantAES_OCB_256,
kWebCryptoCipherDecrypt,
kWebCryptoCipherEncrypt,
} = internalBinding('crypto');
@@ -47,6 +50,7 @@ const {
InternalCryptoKey,
SecretKeyObject,
createSecretKey,
+ kAlgorithm,
} = require('internal/crypto/keys');
const {
@@ -61,6 +65,7 @@ function getAlgorithmName(name, length) {
case 'AES-CTR': return `A${length}CTR`;
case 'AES-GCM': return `A${length}GCM`;
case 'AES-KW': return `A${length}KW`;
+ case 'AES-OCB': return `A${length}OCB`;
}
}
@@ -99,6 +104,13 @@ function getVariant(name, length) {
case 256: return kKeyVariantAES_KW_256;
}
break;
+ case 'AES-OCB':
+ switch (length) {
+ case 128: return kKeyVariantAES_OCB_128;
+ case 192: return kKeyVariantAES_OCB_192;
+ case 256: return kKeyVariantAES_OCB_256;
+ }
+ break;
}
}
@@ -108,7 +120,7 @@ function asyncAesCtrCipher(mode, key, data, algorithm) {
mode,
key[kKeyObject][kHandle],
data,
- getVariant('AES-CTR', key.algorithm.length),
+ getVariant('AES-CTR', key[kAlgorithm].length),
algorithm.counter,
algorithm.length));
}
@@ -119,7 +131,7 @@ function asyncAesCbcCipher(mode, key, data, algorithm) {
mode,
key[kKeyObject][kHandle],
data,
- getVariant('AES-CBC', key.algorithm.length),
+ getVariant('AES-CBC', key[kAlgorithm].length),
algorithm.iv));
}
@@ -129,7 +141,7 @@ function asyncAesKwCipher(mode, key, data) {
mode,
key[kKeyObject][kHandle],
data,
- getVariant('AES-KW', key.algorithm.length)));
+ getVariant('AES-KW', key[kAlgorithm].length)));
}
function asyncAesGcmCipher(mode, key, data, algorithm) {
@@ -166,7 +178,44 @@ function asyncAesGcmCipher(mode, key, data, algorithm) {
mode,
key[kKeyObject][kHandle],
data,
- getVariant('AES-GCM', key.algorithm.length),
+ getVariant('AES-GCM', key[kAlgorithm].length),
+ algorithm.iv,
+ tag,
+ algorithm.additionalData));
+}
+
+function asyncAesOcbCipher(mode, key, data, algorithm) {
+ const { tagLength = 128 } = algorithm;
+
+ const tagByteLength = tagLength / 8;
+ let tag;
+ switch (mode) {
+ case kWebCryptoCipherDecrypt: {
+ const slice = ArrayBufferIsView(data) ?
+ TypedArrayPrototypeSlice : ArrayBufferPrototypeSlice;
+ tag = slice(data, -tagByteLength);
+
+ // Similar to GCM, OCB requires the tag to be present for decryption
+ if (tagByteLength > tag.byteLength) {
+ return PromiseReject(lazyDOMException(
+ 'The provided data is too small.',
+ 'OperationError'));
+ }
+
+ data = slice(data, 0, -tagByteLength);
+ break;
+ }
+ case kWebCryptoCipherEncrypt:
+ tag = tagByteLength;
+ break;
+ }
+
+ return jobPromise(() => new AESCipherJob(
+ kCryptoJobAsync,
+ mode,
+ key[kKeyObject][kHandle],
+ data,
+ getVariant('AES-OCB', key.algorithm.length),
algorithm.iv,
tag,
algorithm.additionalData));
@@ -177,6 +226,7 @@ function aesCipher(mode, key, data, algorithm) {
case 'AES-CTR': return asyncAesCtrCipher(mode, key, data, algorithm);
case 'AES-CBC': return asyncAesCbcCipher(mode, key, data, algorithm);
case 'AES-GCM': return asyncAesGcmCipher(mode, key, data, algorithm);
+ case 'AES-OCB': return asyncAesOcbCipher(mode, key, data, algorithm);
case 'AES-KW': return asyncAesKwCipher(mode, key, data);
}
}
@@ -235,7 +285,11 @@ function aesImportKey(
keyObject = keyData;
break;
}
+ case 'raw-secret':
case 'raw': {
+ if (format === 'raw' && name === 'AES-OCB') {
+ return undefined;
+ }
validateKeyLength(keyData.byteLength * 8);
keyObject = createSecretKey(keyData);
break;
diff --git a/lib/internal/crypto/argon2.js b/lib/internal/crypto/argon2.js
new file mode 100644
index 00000000000000..a17b9ed643d8b5
--- /dev/null
+++ b/lib/internal/crypto/argon2.js
@@ -0,0 +1,185 @@
+'use strict';
+
+const {
+ FunctionPrototypeCall,
+ MathPow,
+ Uint8Array,
+} = primordials;
+
+const { Buffer } = require('buffer');
+
+const {
+ Argon2Job,
+ kCryptoJobAsync,
+ kCryptoJobSync,
+ kTypeArgon2d,
+ kTypeArgon2i,
+ kTypeArgon2id,
+} = internalBinding('crypto');
+
+const { getArrayBufferOrView } = require('internal/crypto/util');
+const {
+ validateString,
+ validateFunction,
+ validateInteger,
+ validateObject,
+ validateOneOf,
+ validateUint32,
+} = require('internal/validators');
+
+const {
+ codes: {
+ ERR_CRYPTO_ARGON2_NOT_SUPPORTED,
+ },
+} = require('internal/errors');
+
+/**
+ * @param {'argon2d' | 'argon2i' | 'argon2id'} algorithm
+ * @param {object} parameters
+ * @param {ArrayBufferLike} parameters.message
+ * @param {ArrayBufferLike} parameters.nonce
+ * @param {number} parameters.parallelism
+ * @param {number} parameters.tagLength
+ * @param {number} parameters.memory
+ * @param {number} parameters.passes
+ * @param {ArrayBufferLike} [parameters.secret]
+ * @param {ArrayBufferLike} [parameters.associatedData]
+ * @param {Function} callback
+ */
+function argon2(algorithm, parameters, callback) {
+ parameters = check(algorithm, parameters);
+
+ validateFunction(callback, 'callback');
+
+ const job = new Argon2Job(
+ kCryptoJobAsync,
+ parameters.message,
+ parameters.nonce,
+ parameters.parallelism,
+ parameters.tagLength,
+ parameters.memory,
+ parameters.passes,
+ parameters.secret,
+ parameters.associatedData,
+ parameters.type);
+
+ job.ondone = (error, result) => {
+ if (error !== undefined)
+ return FunctionPrototypeCall(callback, job, error);
+ const buf = Buffer.from(result);
+ return FunctionPrototypeCall(callback, job, null, buf);
+ };
+
+ job.run();
+}
+
+/**
+ * @param {'argon2d' | 'argon2i' | 'argon2id'} algorithm
+ * @param {object} parameters
+ * @param {ArrayBufferLike} parameters.message
+ * @param {ArrayBufferLike} parameters.nonce
+ * @param {number} parameters.parallelism
+ * @param {number} parameters.tagLength
+ * @param {number} parameters.memory
+ * @param {number} parameters.passes
+ * @param {ArrayBufferLike} [parameters.secret]
+ * @param {ArrayBufferLike} [parameters.associatedData]
+ * @returns {Buffer}
+ */
+function argon2Sync(algorithm, parameters) {
+ parameters = check(algorithm, parameters);
+
+ const job = new Argon2Job(
+ kCryptoJobSync,
+ parameters.message,
+ parameters.nonce,
+ parameters.parallelism,
+ parameters.tagLength,
+ parameters.memory,
+ parameters.passes,
+ parameters.secret,
+ parameters.associatedData,
+ parameters.type);
+
+ const { 0: err, 1: result } = job.run();
+
+ if (err !== undefined)
+ throw err;
+
+ return Buffer.from(result);
+}
+
+/**
+ * @param {'argon2d' | 'argon2i' | 'argon2id'} algorithm
+ * @param {object} parameters
+ * @param {ArrayBufferLike} parameters.message
+ * @param {ArrayBufferLike} parameters.nonce
+ * @param {number} parameters.parallelism
+ * @param {number} parameters.tagLength
+ * @param {number} parameters.memory
+ * @param {number} parameters.passes
+ * @param {ArrayBufferLike} [parameters.secret]
+ * @param {ArrayBufferLike} [parameters.associatedData]
+ * @returns {object}
+ */
+function check(algorithm, parameters) {
+ if (Argon2Job === undefined)
+ throw new ERR_CRYPTO_ARGON2_NOT_SUPPORTED();
+
+ validateString(algorithm, 'algorithm');
+ validateOneOf(algorithm, 'algorithm', ['argon2d', 'argon2i', 'argon2id']);
+
+ let type;
+ switch (algorithm) {
+ case 'argon2d':
+ type = kTypeArgon2d;
+ break;
+ case 'argon2i':
+ type = kTypeArgon2i;
+ break;
+ case 'argon2id':
+ type = kTypeArgon2id;
+ break;
+ default: // unreachable
+ throw new ERR_CRYPTO_ARGON2_NOT_SUPPORTED();
+ }
+
+ validateObject(parameters, 'parameters');
+
+ const { parallelism, tagLength, memory, passes } = parameters;
+ const MAX_POSITIVE_UINT_32 = MathPow(2, 32) - 1;
+
+ const message = getArrayBufferOrView(parameters.message, 'parameters.message');
+ validateInteger(message.byteLength, 'parameters.message.byteLength', 0, MAX_POSITIVE_UINT_32);
+
+ const nonce = getArrayBufferOrView(parameters.nonce, 'parameters.nonce');
+ validateInteger(nonce.byteLength, 'parameters.nonce.byteLength', 8, MAX_POSITIVE_UINT_32);
+
+ validateInteger(parallelism, 'parameters.parallelism', 1, MathPow(2, 24) - 1);
+ validateInteger(tagLength, 'parameters.tagLength', 4, MAX_POSITIVE_UINT_32);
+ validateInteger(memory, 'parameters.memory', 8 * parallelism, MAX_POSITIVE_UINT_32);
+ validateUint32(passes, 'parameters.passes', true);
+
+ let secret;
+ if (parameters.secret === undefined) {
+ secret = new Uint8Array(0);
+ } else {
+ secret = getArrayBufferOrView(parameters.secret);
+ validateInteger(secret.byteLength, 'parameters.secret.byteLength', 0, MAX_POSITIVE_UINT_32);
+ }
+
+ let associatedData;
+ if (parameters.associatedData === undefined) {
+ associatedData = new Uint8Array(0);
+ } else {
+ associatedData = getArrayBufferOrView(parameters.associatedData);
+ validateInteger(associatedData.byteLength, 'parameters.associatedData.byteLength', 0, MAX_POSITIVE_UINT_32);
+ }
+
+ return { message, nonce, secret, associatedData, tagLength, passes, parallelism, memory, type };
+}
+
+module.exports = {
+ argon2,
+ argon2Sync,
+};
diff --git a/lib/internal/crypto/cfrg.js b/lib/internal/crypto/cfrg.js
index e8af5750a865fd..97272ab1672021 100644
--- a/lib/internal/crypto/cfrg.js
+++ b/lib/internal/crypto/cfrg.js
@@ -47,6 +47,7 @@ const {
PublicKeyObject,
createPrivateKey,
createPublicKey,
+ kKeyType,
} = require('internal/crypto/keys');
const generateKeyPair = promisify(_generateKeyPair);
@@ -343,7 +344,7 @@ function eddsaSignVerify(key, data, algorithm, signature) {
const mode = signature === undefined ? kSignJobModeSign : kSignJobModeVerify;
const type = mode === kSignJobModeSign ? 'private' : 'public';
- if (key.type !== type)
+ if (key[kKeyType] !== type)
throw lazyDOMException(`Key must be a ${type} key`, 'InvalidAccessError');
return jobPromise(() => new SignJob(
diff --git a/lib/internal/crypto/chacha20_poly1305.js b/lib/internal/crypto/chacha20_poly1305.js
new file mode 100644
index 00000000000000..bcc778b24d7738
--- /dev/null
+++ b/lib/internal/crypto/chacha20_poly1305.js
@@ -0,0 +1,191 @@
+'use strict';
+
+const {
+ ArrayBufferIsView,
+ ArrayBufferPrototypeSlice,
+ ArrayFrom,
+ PromiseReject,
+ SafeSet,
+ TypedArrayPrototypeSlice,
+} = primordials;
+
+const {
+ ChaCha20Poly1305CipherJob,
+ KeyObjectHandle,
+ kCryptoJobAsync,
+ kWebCryptoCipherDecrypt,
+ kWebCryptoCipherEncrypt,
+} = internalBinding('crypto');
+
+const {
+ hasAnyNotIn,
+ jobPromise,
+ validateKeyOps,
+ kHandle,
+ kKeyObject,
+} = require('internal/crypto/util');
+
+const {
+ lazyDOMException,
+ promisify,
+} = require('internal/util');
+
+const {
+ InternalCryptoKey,
+ SecretKeyObject,
+ createSecretKey,
+} = require('internal/crypto/keys');
+
+const {
+ randomBytes: _randomBytes,
+} = require('internal/crypto/random');
+
+const randomBytes = promisify(_randomBytes);
+
+function validateKeyLength(length) {
+ if (length !== 256)
+ throw lazyDOMException('Invalid key length', 'DataError');
+}
+
+function c20pCipher(mode, key, data, algorithm) {
+ let tag;
+ switch (mode) {
+ case kWebCryptoCipherDecrypt: {
+ const slice = ArrayBufferIsView(data) ?
+ TypedArrayPrototypeSlice : ArrayBufferPrototypeSlice;
+
+ if (data.byteLength < 16) {
+ return PromiseReject(lazyDOMException(
+ 'The provided data is too small.',
+ 'OperationError'));
+ }
+
+ tag = slice(data, -16);
+ data = slice(data, 0, -16);
+ break;
+ }
+ case kWebCryptoCipherEncrypt:
+ tag = 16;
+ break;
+ }
+
+ return jobPromise(() => new ChaCha20Poly1305CipherJob(
+ kCryptoJobAsync,
+ mode,
+ key[kKeyObject][kHandle],
+ data,
+ algorithm.iv,
+ tag,
+ algorithm.additionalData));
+}
+
+async function c20pGenerateKey(algorithm, extractable, keyUsages) {
+ const { name } = algorithm;
+
+ const checkUsages = ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey'];
+
+ const usagesSet = new SafeSet(keyUsages);
+ if (hasAnyNotIn(usagesSet, checkUsages)) {
+ throw lazyDOMException(
+ `Unsupported key usage for a ${algorithm.name} key`,
+ 'SyntaxError');
+ }
+
+ const keyData = await randomBytes(32).catch((err) => {
+ throw lazyDOMException(
+ 'The operation failed for an operation-specific reason' +
+ `[${err.message}]`,
+ { name: 'OperationError', cause: err });
+ });
+
+ return new InternalCryptoKey(
+ createSecretKey(keyData),
+ { name },
+ ArrayFrom(usagesSet),
+ extractable);
+}
+
+function c20pImportKey(
+ algorithm,
+ format,
+ keyData,
+ extractable,
+ keyUsages) {
+ const { name } = algorithm;
+ const checkUsages = ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey'];
+
+ const usagesSet = new SafeSet(keyUsages);
+ if (hasAnyNotIn(usagesSet, checkUsages)) {
+ throw lazyDOMException(
+ `Unsupported key usage for a ${algorithm.name} key`,
+ 'SyntaxError');
+ }
+
+ let keyObject;
+ switch (format) {
+ case 'KeyObject': {
+ keyObject = keyData;
+ break;
+ }
+ case 'raw-secret': {
+ keyObject = createSecretKey(keyData);
+ break;
+ }
+ case 'jwk': {
+ if (!keyData.kty)
+ throw lazyDOMException('Invalid keyData', 'DataError');
+
+ if (keyData.kty !== 'oct')
+ throw lazyDOMException('Invalid JWK "kty" Parameter', 'DataError');
+
+ if (usagesSet.size > 0 &&
+ keyData.use !== undefined &&
+ keyData.use !== 'enc') {
+ throw lazyDOMException('Invalid JWK "use" Parameter', 'DataError');
+ }
+
+ validateKeyOps(keyData.key_ops, usagesSet);
+
+ if (keyData.ext !== undefined &&
+ keyData.ext === false &&
+ extractable === true) {
+ throw lazyDOMException(
+ 'JWK "ext" Parameter and extractable mismatch',
+ 'DataError');
+ }
+
+ const handle = new KeyObjectHandle();
+ try {
+ handle.initJwk(keyData);
+ } catch (err) {
+ throw lazyDOMException(
+ 'Invalid keyData', { name: 'DataError', cause: err });
+ }
+
+ if (keyData.alg !== undefined && keyData.alg !== 'C20P') {
+ throw lazyDOMException(
+ 'JWK "alg" does not match the requested algorithm',
+ 'DataError');
+ }
+
+ keyObject = new SecretKeyObject(handle);
+ break;
+ }
+ default:
+ return undefined;
+ }
+
+ validateKeyLength(keyObject.symmetricKeySize * 8);
+
+ return new InternalCryptoKey(
+ keyObject,
+ { name },
+ keyUsages,
+ extractable);
+}
+
+module.exports = {
+ c20pCipher,
+ c20pGenerateKey,
+ c20pImportKey,
+};
diff --git a/lib/internal/crypto/diffiehellman.js b/lib/internal/crypto/diffiehellman.js
index 24ff71fca83f31..1712996f670dbe 100644
--- a/lib/internal/crypto/diffiehellman.js
+++ b/lib/internal/crypto/diffiehellman.js
@@ -51,6 +51,8 @@ const {
const {
KeyObject,
+ kAlgorithm,
+ kKeyType,
} = require('internal/crypto/keys');
const {
@@ -325,20 +327,20 @@ let masks;
async function ecdhDeriveBits(algorithm, baseKey, length) {
const { 'public': key } = algorithm;
- if (baseKey.type !== 'private') {
+ if (baseKey[kKeyType] !== 'private') {
throw lazyDOMException(
'baseKey must be a private key', 'InvalidAccessError');
}
- if (key.algorithm.name !== baseKey.algorithm.name) {
+ if (key[kAlgorithm].name !== baseKey[kAlgorithm].name) {
throw lazyDOMException(
'The public and private keys must be of the same type',
'InvalidAccessError');
}
if (
- key.algorithm.name === 'ECDH' &&
- key.algorithm.namedCurve !== baseKey.algorithm.namedCurve
+ key[kAlgorithm].name === 'ECDH' &&
+ key[kAlgorithm].namedCurve !== baseKey[kAlgorithm].namedCurve
) {
throw lazyDOMException('Named curve mismatch', 'InvalidAccessError');
}
diff --git a/lib/internal/crypto/ec.js b/lib/internal/crypto/ec.js
index f4ea317b86ee73..52791412835300 100644
--- a/lib/internal/crypto/ec.js
+++ b/lib/internal/crypto/ec.js
@@ -41,6 +41,7 @@ const {
PublicKeyObject,
createPrivateKey,
createPublicKey,
+ kKeyType,
} = require('internal/crypto/keys');
const generateKeyPair = promisify(_generateKeyPair);
@@ -284,7 +285,7 @@ function ecdsaSignVerify(key, data, { name, hash }, signature) {
const mode = signature === undefined ? kSignJobModeSign : kSignJobModeVerify;
const type = mode === kSignJobModeSign ? 'private' : 'public';
- if (key.type !== type)
+ if (key[kKeyType] !== type)
throw lazyDOMException(`Key must be a ${type} key`, 'InvalidAccessError');
const hashname = normalizeHashName(hash.name);
diff --git a/lib/internal/crypto/hash.js b/lib/internal/crypto/hash.js
index 9937dbceb2c4d7..e4d94da1c5ee96 100644
--- a/lib/internal/crypto/hash.js
+++ b/lib/internal/crypto/hash.js
@@ -211,10 +211,21 @@ async function asyncDigest(algorithm, data) {
case 'SHA-384':
// Fall through
case 'SHA-512':
+ // Fall through
+ case 'SHA3-256':
+ // Fall through
+ case 'SHA3-384':
+ // Fall through
+ case 'SHA3-512':
+ // Fall through
+ case 'cSHAKE128':
+ // Fall through
+ case 'cSHAKE256':
return jobPromise(() => new HashJob(
kCryptoJobAsync,
normalizeHashName(algorithm.name),
- data));
+ data,
+ algorithm.length));
}
throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
diff --git a/lib/internal/crypto/hashnames.js b/lib/internal/crypto/hashnames.js
index 7af2091d84de39..7a625c47e2f4b2 100644
--- a/lib/internal/crypto/hashnames.js
+++ b/lib/internal/crypto/hashnames.js
@@ -17,7 +17,7 @@ const kHashContextJwkHmac = 6;
// make it easier in the code.
const kHashNames = {
- sha1: {
+ 'sha1': {
[kHashContextNode]: 'sha1',
[kHashContextWebCrypto]: 'SHA-1',
[kHashContextJwkRsa]: 'RS1',
@@ -25,7 +25,7 @@ const kHashNames = {
[kHashContextJwkRsaOaep]: 'RSA-OAEP',
[kHashContextJwkHmac]: 'HS1',
},
- sha256: {
+ 'sha256': {
[kHashContextNode]: 'sha256',
[kHashContextWebCrypto]: 'SHA-256',
[kHashContextJwkRsa]: 'RS256',
@@ -33,7 +33,7 @@ const kHashNames = {
[kHashContextJwkRsaOaep]: 'RSA-OAEP-256',
[kHashContextJwkHmac]: 'HS256',
},
- sha384: {
+ 'sha384': {
[kHashContextNode]: 'sha384',
[kHashContextWebCrypto]: 'SHA-384',
[kHashContextJwkRsa]: 'RS384',
@@ -41,7 +41,7 @@ const kHashNames = {
[kHashContextJwkRsaOaep]: 'RSA-OAEP-384',
[kHashContextJwkHmac]: 'HS384',
},
- sha512: {
+ 'sha512': {
[kHashContextNode]: 'sha512',
[kHashContextWebCrypto]: 'SHA-512',
[kHashContextJwkRsa]: 'RS512',
@@ -49,6 +49,26 @@ const kHashNames = {
[kHashContextJwkRsaOaep]: 'RSA-OAEP-512',
[kHashContextJwkHmac]: 'HS512',
},
+ 'shake128': {
+ [kHashContextNode]: 'shake128',
+ [kHashContextWebCrypto]: 'cSHAKE128',
+ },
+ 'shake256': {
+ [kHashContextNode]: 'shake256',
+ [kHashContextWebCrypto]: 'cSHAKE256',
+ },
+ 'sha3-256': {
+ [kHashContextNode]: 'sha3-256',
+ [kHashContextWebCrypto]: 'SHA3-256',
+ },
+ 'sha3-384': {
+ [kHashContextNode]: 'sha3-384',
+ [kHashContextWebCrypto]: 'SHA3-384',
+ },
+ 'sha3-512': {
+ [kHashContextNode]: 'sha3-512',
+ [kHashContextWebCrypto]: 'SHA3-512',
+ },
};
{
diff --git a/lib/internal/crypto/hkdf.js b/lib/internal/crypto/hkdf.js
index 9b4d1469cc9df5..1a5e9ccd06813e 100644
--- a/lib/internal/crypto/hkdf.js
+++ b/lib/internal/crypto/hkdf.js
@@ -170,4 +170,5 @@ module.exports = {
hkdf,
hkdfSync,
hkdfDeriveBits,
+ validateHkdfDeriveBitsLength,
};
diff --git a/lib/internal/crypto/kem.js b/lib/internal/crypto/kem.js
new file mode 100644
index 00000000000000..43c7bde52ea99f
--- /dev/null
+++ b/lib/internal/crypto/kem.js
@@ -0,0 +1,112 @@
+'use strict';
+
+const {
+ FunctionPrototypeCall,
+} = primordials;
+
+const {
+ codes: {
+ ERR_CRYPTO_KEM_NOT_SUPPORTED,
+ },
+} = require('internal/errors');
+
+const {
+ validateFunction,
+} = require('internal/validators');
+
+const {
+ kCryptoJobAsync,
+ kCryptoJobSync,
+ KEMDecapsulateJob,
+ KEMEncapsulateJob,
+} = internalBinding('crypto');
+
+const {
+ preparePrivateKey,
+ preparePublicOrPrivateKey,
+} = require('internal/crypto/keys');
+
+const {
+ getArrayBufferOrView,
+} = require('internal/crypto/util');
+
+function encapsulate(key, callback) {
+ if (!KEMEncapsulateJob)
+ throw new ERR_CRYPTO_KEM_NOT_SUPPORTED();
+
+ if (callback !== undefined)
+ validateFunction(callback, 'callback');
+
+ const {
+ data: keyData,
+ format: keyFormat,
+ type: keyType,
+ passphrase: keyPassphrase,
+ } = preparePublicOrPrivateKey(key);
+
+ const job = new KEMEncapsulateJob(
+ callback ? kCryptoJobAsync : kCryptoJobSync,
+ keyData,
+ keyFormat,
+ keyType,
+ keyPassphrase);
+
+ if (!callback) {
+ const { 0: err, 1: result } = job.run();
+ if (err !== undefined)
+ throw err;
+ const { 0: sharedKey, 1: ciphertext } = result;
+ return { sharedKey, ciphertext };
+ }
+
+ job.ondone = (error, result) => {
+ if (error) return FunctionPrototypeCall(callback, job, error);
+ const { 0: sharedKey, 1: ciphertext } = result;
+ FunctionPrototypeCall(callback, job, null, { sharedKey, ciphertext });
+ };
+ job.run();
+}
+
+function decapsulate(key, ciphertext, callback) {
+ if (!KEMDecapsulateJob)
+ throw new ERR_CRYPTO_KEM_NOT_SUPPORTED();
+
+ if (callback !== undefined)
+ validateFunction(callback, 'callback');
+
+ const {
+ data: keyData,
+ format: keyFormat,
+ type: keyType,
+ passphrase: keyPassphrase,
+ } = preparePrivateKey(key);
+
+ ciphertext = getArrayBufferOrView(ciphertext, 'ciphertext');
+
+ const job = new KEMDecapsulateJob(
+ callback ? kCryptoJobAsync : kCryptoJobSync,
+ keyData,
+ keyFormat,
+ keyType,
+ keyPassphrase,
+ ciphertext);
+
+ if (!callback) {
+ const { 0: err, 1: result } = job.run();
+ if (err !== undefined)
+ throw err;
+
+ return result;
+ }
+
+ job.ondone = (error, result) => {
+ if (error) return FunctionPrototypeCall(callback, job, error);
+ FunctionPrototypeCall(callback, job, null, result);
+ };
+ job.run();
+}
+
+module.exports = {
+ encapsulate,
+ decapsulate,
+};
diff --git a/lib/internal/crypto/keygen.js b/lib/internal/crypto/keygen.js
index cb46b72c59a5ca..9c0aded1538f26 100644
--- a/lib/internal/crypto/keygen.js
+++ b/lib/internal/crypto/keygen.js
@@ -22,6 +22,9 @@ const {
EVP_PKEY_ML_DSA_44,
EVP_PKEY_ML_DSA_65,
EVP_PKEY_ML_DSA_87,
+ EVP_PKEY_ML_KEM_1024,
+ EVP_PKEY_ML_KEM_512,
+ EVP_PKEY_ML_KEM_768,
EVP_PKEY_X25519,
EVP_PKEY_X448,
OPENSSL_EC_NAMED_CURVE,
@@ -173,6 +176,9 @@ const ids = {
'ml-dsa-44': EVP_PKEY_ML_DSA_44,
'ml-dsa-65': EVP_PKEY_ML_DSA_65,
'ml-dsa-87': EVP_PKEY_ML_DSA_87,
+ 'ml-kem-512': EVP_PKEY_ML_KEM_512,
+ 'ml-kem-768': EVP_PKEY_ML_KEM_768,
+ 'ml-kem-1024': EVP_PKEY_ML_KEM_1024,
};
function createJob(mode, type, options) {
@@ -294,6 +300,9 @@ function createJob(mode, type, options) {
case 'ml-dsa-44':
case 'ml-dsa-65':
case 'ml-dsa-87':
+ case 'ml-kem-512':
+ case 'ml-kem-768':
+ case 'ml-kem-1024':
{
if (ids[type] === undefined) {
throw new ERR_INVALID_ARG_VALUE('type', type, 'must be a supported key type');
diff --git a/lib/internal/crypto/keys.js b/lib/internal/crypto/keys.js
index 60b4d26d35e967..c8b3d870ac5225 100644
--- a/lib/internal/crypto/keys.js
+++ b/lib/internal/crypto/keys.js
@@ -1,6 +1,7 @@
'use strict';
const {
+ ArrayFrom,
ArrayPrototypeSlice,
ObjectDefineProperties,
ObjectDefineProperty,
@@ -81,6 +82,8 @@ const kAlgorithm = Symbol('kAlgorithm');
const kExtractable = Symbol('kExtractable');
const kKeyType = Symbol('kKeyType');
const kKeyUsages = Symbol('kKeyUsages');
+const kCachedAlgorithm = Symbol('kCachedAlgorithm');
+const kCachedKeyUsages = Symbol('kCachedKeyUsages');
// Key input contexts.
const kConsumePublic = 0;
@@ -196,9 +199,15 @@ const {
case 'AES-GCM':
// Fall through
case 'AES-KW':
+ // Fall through
+ case 'AES-OCB':
result = require('internal/crypto/aes')
.aesImportKey(algorithm, 'KeyObject', this, extractable, keyUsages);
break;
+ case 'ChaCha20-Poly1305':
+ result = require('internal/crypto/chacha20_poly1305')
+ .c20pImportKey(algorithm, 'KeyObject', this, extractable, keyUsages);
+ break;
case 'HKDF':
// Fall through
case 'PBKDF2':
@@ -213,7 +222,7 @@ const {
throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
}
- if (result.usages.length === 0) {
+ if (result[kKeyUsages].length === 0) {
throw lazyDOMException(
`Usages cannot be empty when importing a ${result.type} key.`,
'SyntaxError');
@@ -293,11 +302,27 @@ const {
result = require('internal/crypto/cfrg')
.cfrgImportKey('KeyObject', this, algorithm, extractable, keyUsages);
break;
+ case 'ML-DSA-44':
+ // Fall through
+ case 'ML-DSA-65':
+ // Fall through
+ case 'ML-DSA-87':
+ result = require('internal/crypto/ml_dsa')
+ .mlDsaImportKey('KeyObject', this, algorithm, extractable, keyUsages);
+ break;
+ case 'ML-KEM-512':
+ // Fall through
+ case 'ML-KEM-768':
+ // Fall through
+ case 'ML-KEM-1024':
+ result = require('internal/crypto/ml_kem')
+ .mlKemImportKey('KeyObject', this, algorithm, extractable, keyUsages);
+ break;
default:
throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
}
- if (result.type === 'private' && result.usages.length === 0) {
+ if (result.type === 'private' && result[kKeyUsages].length === 0) {
throw lazyDOMException(
`Usages cannot be empty when importing a ${result.type} key.`,
'SyntaxError');
@@ -553,7 +578,7 @@ function getKeyObjectHandleFromJwk(key, ctx) {
const handle = new KeyObjectHandle();
const keyType = isPublic ? kKeyTypePublic : kKeyTypePrivate;
- if (!handle.initMlDsaRaw(key.alg, keyData, keyType)) {
+ if (!handle.initPqcRaw(key.alg, keyData, keyType)) {
throw new ERR_CRYPTO_INVALID_JWK();
}
@@ -723,8 +748,8 @@ function prepareSecretKey(key, encoding, bufferOnly = false) {
throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(key.type, 'secret');
return key[kHandle];
} else if (isCryptoKey(key)) {
- if (key.type !== 'secret')
- throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(key.type, 'secret');
+ if (key[kKeyType] !== 'secret')
+ throw new ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE(key[kKeyType], 'secret');
return key[kKeyObject][kHandle];
}
}
@@ -773,7 +798,7 @@ function createPrivateKey(key) {
}
function isKeyObject(obj) {
- return obj != null && obj[kKeyType] !== undefined;
+ return obj != null && obj[kKeyType] !== undefined && obj[kKeyObject] === undefined;
}
// Our implementation of CryptoKey is a simple wrapper around a KeyObject
@@ -797,17 +822,21 @@ class CryptoKey {
};
return `CryptoKey ${inspect({
- type: this.type,
- extractable: this.extractable,
- algorithm: this.algorithm,
- usages: this.usages,
+ type: this[kKeyType],
+ extractable: this[kExtractable],
+ algorithm: this[kAlgorithm],
+ usages: this[kKeyUsages],
}, opts)}`;
}
+ get [kKeyType]() {
+ return this[kKeyObject].type;
+ }
+
get type() {
if (!(this instanceof CryptoKey))
throw new ERR_INVALID_THIS('CryptoKey');
- return this[kKeyObject].type;
+ return this[kKeyType];
}
get extractable() {
@@ -819,13 +848,19 @@ class CryptoKey {
get algorithm() {
if (!(this instanceof CryptoKey))
throw new ERR_INVALID_THIS('CryptoKey');
- return this[kAlgorithm];
+ if (!this[kCachedAlgorithm]) {
+ this[kCachedAlgorithm] ??= { ...this[kAlgorithm] };
+ this[kCachedAlgorithm].hash &&= { ...this[kCachedAlgorithm].hash };
+ this[kCachedAlgorithm].publicExponent &&= new Uint8Array(this[kCachedAlgorithm].publicExponent);
+ }
+ return this[kCachedAlgorithm];
}
get usages() {
if (!(this instanceof CryptoKey))
throw new ERR_INVALID_THIS('CryptoKey');
- return this[kKeyUsages];
+ this[kCachedKeyUsages] ??= ArrayFrom(this[kKeyUsages]);
+ return this[kCachedKeyUsages];
}
}
@@ -996,4 +1031,8 @@ module.exports = {
isKeyObject,
isCryptoKey,
importGenericSecretKey,
+ kAlgorithm,
+ kExtractable,
+ kKeyType,
+ kKeyUsages,
};
diff --git a/lib/internal/crypto/mac.js b/lib/internal/crypto/mac.js
index 0f9b1f9618d260..ed30a64ba239ea 100644
--- a/lib/internal/crypto/mac.js
+++ b/lib/internal/crypto/mac.js
@@ -36,6 +36,7 @@ const {
InternalCryptoKey,
SecretKeyObject,
createSecretKey,
+ kAlgorithm,
} = require('internal/crypto/keys');
const generateKey = promisify(_generateKey);
@@ -62,23 +63,11 @@ async function hmacGenerateKey(algorithm, extractable, keyUsages) {
return new InternalCryptoKey(
key,
- { name, length, hash: { name: hash.name } },
+ { name, length, hash },
ArrayFrom(usageSet),
extractable);
}
-function getAlgorithmName(hash) {
- switch (hash) {
- case 'SHA-1': // Fall through
- case 'SHA-256': // Fall through
- case 'SHA-384': // Fall through
- case 'SHA-512': // Fall through
- return `HS${hash.slice(4)}`;
- default:
- throw lazyDOMException('Unsupported digest algorithm', 'DataError');
- }
-}
-
function hmacImportKey(
format,
keyData,
@@ -126,7 +115,9 @@ function hmacImportKey(
}
if (keyData.alg !== undefined) {
- if (keyData.alg !== getAlgorithmName(algorithm.hash.name))
+ const expected =
+ normalizeHashName(algorithm.hash.name, normalizeHashName.kContextJwkHmac);
+ if (expected && keyData.alg !== expected)
throw lazyDOMException(
'JWK "alg" does not match the requested algorithm',
'DataError');
@@ -171,7 +162,7 @@ function hmacSignVerify(key, data, algorithm, signature) {
return jobPromise(() => new HmacJob(
kCryptoJobAsync,
mode,
- normalizeHashName(key.algorithm.hash.name),
+ normalizeHashName(key[kAlgorithm].hash.name),
key[kKeyObject][kHandle],
data,
signature));
diff --git a/lib/internal/crypto/ml_dsa.js b/lib/internal/crypto/ml_dsa.js
new file mode 100644
index 00000000000000..966f5b0d222fd0
--- /dev/null
+++ b/lib/internal/crypto/ml_dsa.js
@@ -0,0 +1,317 @@
+'use strict';
+
+const {
+ SafeSet,
+ Uint8Array,
+} = primordials;
+
+const { Buffer } = require('buffer');
+
+const {
+ KeyObjectHandle,
+ SignJob,
+ kCryptoJobAsync,
+ kKeyTypePrivate,
+ kKeyTypePublic,
+ kSignJobModeSign,
+ kSignJobModeVerify,
+ kKeyFormatDER,
+ kWebCryptoKeyFormatRaw,
+ kWebCryptoKeyFormatPKCS8,
+ kWebCryptoKeyFormatSPKI,
+} = internalBinding('crypto');
+
+const {
+ codes: {
+ ERR_CRYPTO_INVALID_JWK,
+ },
+} = require('internal/errors');
+
+const {
+ getUsagesUnion,
+ hasAnyNotIn,
+ jobPromise,
+ validateKeyOps,
+ kHandle,
+ kKeyObject,
+} = require('internal/crypto/util');
+
+const {
+ lazyDOMException,
+ promisify,
+} = require('internal/util');
+
+const {
+ generateKeyPair: _generateKeyPair,
+} = require('internal/crypto/keygen');
+
+const {
+ InternalCryptoKey,
+ PrivateKeyObject,
+ PublicKeyObject,
+ createPrivateKey,
+ createPublicKey,
+ kAlgorithm,
+ kKeyType,
+} = require('internal/crypto/keys');
+
+const generateKeyPair = promisify(_generateKeyPair);
+
+function verifyAcceptableMlDsaKeyUse(name, isPublic, usages) {
+ const checkSet = isPublic ? ['verify'] : ['sign'];
+ if (hasAnyNotIn(usages, checkSet)) {
+ throw lazyDOMException(
+ `Unsupported key usage for a ${name} key`,
+ 'SyntaxError');
+ }
+}
+
+function createMlDsaRawKey(name, keyData, isPublic) {
+ const handle = new KeyObjectHandle();
+ const keyType = isPublic ? kKeyTypePublic : kKeyTypePrivate;
+ if (!handle.initPqcRaw(name, keyData, keyType)) {
+ throw lazyDOMException('Invalid keyData', 'DataError');
+ }
+
+ return isPublic ? new PublicKeyObject(handle) : new PrivateKeyObject(handle);
+}
+
+async function mlDsaGenerateKey(algorithm, extractable, keyUsages) {
+ const { name } = algorithm;
+
+ const usageSet = new SafeSet(keyUsages);
+ if (hasAnyNotIn(usageSet, ['sign', 'verify'])) {
+ throw lazyDOMException(
+ `Unsupported key usage for an ${name} key`,
+ 'SyntaxError');
+ }
+
+ const keyPair = await generateKeyPair(name.toLowerCase()).catch((err) => {
+ throw lazyDOMException(
+ 'The operation failed for an operation-specific reason',
+ { name: 'OperationError', cause: err });
+ });
+
+ const publicUsages = getUsagesUnion(usageSet, 'verify');
+ const privateUsages = getUsagesUnion(usageSet, 'sign');
+
+ const keyAlgorithm = { name };
+
+ const publicKey =
+ new InternalCryptoKey(
+ keyPair.publicKey,
+ keyAlgorithm,
+ publicUsages,
+ true);
+
+ const privateKey =
+ new InternalCryptoKey(
+ keyPair.privateKey,
+ keyAlgorithm,
+ privateUsages,
+ extractable);
+
+ return { __proto__: null, privateKey, publicKey };
+}
+
+function mlDsaExportKey(key, format) {
+ try {
+ switch (format) {
+ case kWebCryptoKeyFormatRaw: {
+ if (key[kKeyType] === 'private') {
+ return key[kKeyObject][kHandle].rawSeed().buffer;
+ }
+
+ return key[kKeyObject][kHandle].rawPublicKey().buffer;
+ }
+ case kWebCryptoKeyFormatSPKI: {
+ return key[kKeyObject][kHandle].export(kKeyFormatDER, kWebCryptoKeyFormatSPKI).buffer;
+ }
+ case kWebCryptoKeyFormatPKCS8: {
+ const seed = key[kKeyObject][kHandle].rawSeed();
+ const buffer = new Uint8Array(54);
+ buffer.set([
+ 0x30, 0x34, 0x02, 0x01, 0x00, 0x30, 0x0B, 0x06,
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
+ 0x03, 0x00, 0x04, 0x22, 0x80, 0x20,
+ ], 0);
+ switch (key[kAlgorithm].name) {
+ case 'ML-DSA-44':
+ buffer.set([0x11], 17);
+ break;
+ case 'ML-DSA-65':
+ buffer.set([0x12], 17);
+ break;
+ case 'ML-DSA-87':
+ buffer.set([0x13], 17);
+ break;
+ }
+ buffer.set(seed, 22);
+ return buffer.buffer;
+ }
+ default:
+ return undefined;
+ }
+ } catch (err) {
+ throw lazyDOMException(
+ 'The operation failed for an operation-specific reason',
+ { name: 'OperationError', cause: err });
+ }
+}
+
+function mlDsaImportKey(
+ format,
+ keyData,
+ algorithm,
+ extractable,
+ keyUsages) {
+
+ const { name } = algorithm;
+ let keyObject;
+ const usagesSet = new SafeSet(keyUsages);
+ switch (format) {
+ case 'KeyObject': {
+ verifyAcceptableMlDsaKeyUse(name, keyData.type === 'public', usagesSet);
+ keyObject = keyData;
+ break;
+ }
+ case 'spki': {
+ verifyAcceptableMlDsaKeyUse(name, true, usagesSet);
+ try {
+ keyObject = createPublicKey({
+ key: keyData,
+ format: 'der',
+ type: 'spki',
+ });
+ } catch (err) {
+ throw lazyDOMException(
+ 'Invalid keyData', { name: 'DataError', cause: err });
+ }
+ break;
+ }
+ case 'pkcs8': {
+ verifyAcceptableMlDsaKeyUse(name, false, usagesSet);
+ try {
+ keyObject = createPrivateKey({
+ key: keyData,
+ format: 'der',
+ type: 'pkcs8',
+ });
+ } catch (err) {
+ throw lazyDOMException(
+ 'Invalid keyData', { name: 'DataError', cause: err });
+ }
+ break;
+ }
+ case 'jwk': {
+ if (!keyData.kty)
+ throw lazyDOMException('Invalid keyData', 'DataError');
+ if (keyData.kty !== 'AKP')
+ throw lazyDOMException('Invalid JWK "kty" Parameter', 'DataError');
+ if (keyData.alg !== name)
+ throw lazyDOMException(
+ 'JWK "alg" Parameter and algorithm name mismatch', 'DataError');
+ const isPublic = keyData.priv === undefined;
+
+ if (usagesSet.size > 0 && keyData.use !== undefined) {
+ if (keyData.use !== 'sig')
+ throw lazyDOMException('Invalid JWK "use" Parameter', 'DataError');
+ }
+
+ validateKeyOps(keyData.key_ops, usagesSet);
+
+ if (keyData.ext !== undefined &&
+ keyData.ext === false &&
+ extractable === true) {
+ throw lazyDOMException(
+ 'JWK "ext" Parameter and extractable mismatch',
+ 'DataError');
+ }
+
+ if (!isPublic && typeof keyData.pub !== 'string') {
+ throw lazyDOMException('Invalid JWK', 'DataError');
+ }
+
+ verifyAcceptableMlDsaKeyUse(
+ name,
+ isPublic,
+ usagesSet);
+
+ try {
+ const publicKeyObject = createMlDsaRawKey(
+ name,
+ Buffer.from(keyData.pub, 'base64url'),
+ true);
+
+ if (isPublic) {
+ keyObject = publicKeyObject;
+ } else {
+ keyObject = createMlDsaRawKey(
+ name,
+ Buffer.from(keyData.priv, 'base64url'),
+ false);
+
+ if (!createPublicKey(keyObject).equals(publicKeyObject)) {
+ throw new ERR_CRYPTO_INVALID_JWK();
+ }
+ }
+ } catch (err) {
+ throw lazyDOMException('Invalid keyData', { name: 'DataError', cause: err });
+ }
+ break;
+ }
+ case 'raw-public':
+ case 'raw-seed': {
+ const isPublic = format === 'raw-public';
+ verifyAcceptableMlDsaKeyUse(name, isPublic, usagesSet);
+
+ try {
+ keyObject = createMlDsaRawKey(name, keyData, isPublic);
+ } catch (err) {
+ throw lazyDOMException('Invalid keyData', { name: 'DataError', cause: err });
+ }
+ break;
+ }
+ default:
+ return undefined;
+ }
+
+ if (keyObject.asymmetricKeyType !== name.toLowerCase()) {
+ throw lazyDOMException('Invalid key type', 'DataError');
+ }
+
+ return new InternalCryptoKey(
+ keyObject,
+ { name },
+ keyUsages,
+ extractable);
+}
+
+function mlDsaSignVerify(key, data, algorithm, signature) {
+ const mode = signature === undefined ? kSignJobModeSign : kSignJobModeVerify;
+ const type = mode === kSignJobModeSign ? 'private' : 'public';
+
+ if (key[kKeyType] !== type)
+ throw lazyDOMException(`Key must be a ${type} key`, 'InvalidAccessError');
+
+ return jobPromise(() => new SignJob(
+ kCryptoJobAsync,
+ mode,
+ key[kKeyObject][kHandle],
+ undefined,
+ undefined,
+ undefined,
+ data,
+ undefined,
+ undefined,
+ undefined,
+ undefined,
+ signature));
+}
+
+module.exports = {
+ mlDsaExportKey,
+ mlDsaImportKey,
+ mlDsaGenerateKey,
+ mlDsaSignVerify,
+};
diff --git a/lib/internal/crypto/ml_kem.js b/lib/internal/crypto/ml_kem.js
new file mode 100644
index 00000000000000..4dfa1fa31a0425
--- /dev/null
+++ b/lib/internal/crypto/ml_kem.js
@@ -0,0 +1,287 @@
+'use strict';
+
+const {
+ PromiseWithResolvers,
+ SafeSet,
+ Uint8Array,
+} = primordials;
+
+const {
+ kCryptoJobAsync,
+ KEMDecapsulateJob,
+ KEMEncapsulateJob,
+ KeyObjectHandle,
+ kKeyFormatDER,
+ kKeyTypePrivate,
+ kKeyTypePublic,
+ kWebCryptoKeyFormatPKCS8,
+ kWebCryptoKeyFormatRaw,
+ kWebCryptoKeyFormatSPKI,
+} = internalBinding('crypto');
+
+const {
+ getUsagesUnion,
+ hasAnyNotIn,
+ kHandle,
+ kKeyObject,
+} = require('internal/crypto/util');
+
+const {
+ lazyDOMException,
+ promisify,
+} = require('internal/util');
+
+const {
+ generateKeyPair: _generateKeyPair,
+} = require('internal/crypto/keygen');
+
+const {
+ InternalCryptoKey,
+ PrivateKeyObject,
+ PublicKeyObject,
+ createPrivateKey,
+ createPublicKey,
+ kAlgorithm,
+ kKeyType,
+} = require('internal/crypto/keys');
+
+const generateKeyPair = promisify(_generateKeyPair);
+
+async function mlKemGenerateKey(algorithm, extractable, keyUsages) {
+ const { name } = algorithm;
+
+ const usageSet = new SafeSet(keyUsages);
+ if (hasAnyNotIn(usageSet, ['encapsulateKey', 'encapsulateBits', 'decapsulateKey', 'decapsulateBits'])) {
+ throw lazyDOMException(
+ `Unsupported key usage for an ${name} key`,
+ 'SyntaxError');
+ }
+
+ const keyPair = await generateKeyPair(name.toLowerCase()).catch((err) => {
+ throw lazyDOMException(
+ 'The operation failed for an operation-specific reason',
+ { name: 'OperationError', cause: err });
+ });
+
+ const publicUsages = getUsagesUnion(usageSet, 'encapsulateBits', 'encapsulateKey');
+ const privateUsages = getUsagesUnion(usageSet, 'decapsulateBits', 'decapsulateKey');
+
+ const keyAlgorithm = { name };
+
+ const publicKey =
+ new InternalCryptoKey(
+ keyPair.publicKey,
+ keyAlgorithm,
+ publicUsages,
+ true);
+
+ const privateKey =
+ new InternalCryptoKey(
+ keyPair.privateKey,
+ keyAlgorithm,
+ privateUsages,
+ extractable);
+
+ return { __proto__: null, privateKey, publicKey };
+}
+
+function mlKemExportKey(key, format) {
+ try {
+ switch (format) {
+ case kWebCryptoKeyFormatRaw: {
+ if (key[kKeyType] === 'private') {
+ return key[kKeyObject][kHandle].rawSeed().buffer;
+ }
+
+ return key[kKeyObject][kHandle].rawPublicKey().buffer;
+ }
+ case kWebCryptoKeyFormatSPKI: {
+ return key[kKeyObject][kHandle].export(kKeyFormatDER, kWebCryptoKeyFormatSPKI).buffer;
+ }
+ case kWebCryptoKeyFormatPKCS8: {
+ const seed = key[kKeyObject][kHandle].rawSeed();
+ const buffer = new Uint8Array(86);
+ buffer.set([
+ 0x30, 0x54, 0x02, 0x01, 0x00, 0x30, 0x0B, 0x06,
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
+ 0x04, 0x00, 0x04, 0x42, 0x80, 0x40,
+ ], 0);
+ switch (key[kAlgorithm].name) {
+ case 'ML-KEM-512':
+ buffer.set([0x01], 17);
+ break;
+ case 'ML-KEM-768':
+ buffer.set([0x02], 17);
+ break;
+ case 'ML-KEM-1024':
+ buffer.set([0x03], 17);
+ break;
+ }
+ buffer.set(seed, 22);
+ return buffer.buffer;
+ }
+ default:
+ return undefined;
+ }
+ } catch (err) {
+ throw lazyDOMException(
+ 'The operation failed for an operation-specific reason',
+ { name: 'OperationError', cause: err });
+ }
+}
+
+function verifyAcceptableMlKemKeyUse(name, isPublic, usages) {
+ const checkSet = isPublic ? ['encapsulateKey', 'encapsulateBits'] : ['decapsulateKey', 'decapsulateBits'];
+ if (hasAnyNotIn(usages, checkSet)) {
+ throw lazyDOMException(
+ `Unsupported key usage for a ${name} key`,
+ 'SyntaxError');
+ }
+}
+
+function createMlKemRawKey(name, keyData, isPublic) {
+ const handle = new KeyObjectHandle();
+ const keyType = isPublic ? kKeyTypePublic : kKeyTypePrivate;
+ if (!handle.initPqcRaw(name, keyData, keyType)) {
+ throw lazyDOMException('Invalid keyData', 'DataError');
+ }
+
+ return isPublic ? new PublicKeyObject(handle) : new PrivateKeyObject(handle);
+}
+
+function mlKemImportKey(
+ format,
+ keyData,
+ algorithm,
+ extractable,
+ keyUsages) {
+
+ const { name } = algorithm;
+ let keyObject;
+ const usagesSet = new SafeSet(keyUsages);
+ switch (format) {
+ case 'KeyObject': {
+ verifyAcceptableMlKemKeyUse(name, keyData.type === 'public', usagesSet);
+ keyObject = keyData;
+ break;
+ }
+ case 'spki': {
+ verifyAcceptableMlKemKeyUse(name, true, usagesSet);
+ try {
+ keyObject = createPublicKey({
+ key: keyData,
+ format: 'der',
+ type: 'spki',
+ });
+ } catch (err) {
+ throw lazyDOMException(
+ 'Invalid keyData', { name: 'DataError', cause: err });
+ }
+ break;
+ }
+ case 'pkcs8': {
+ verifyAcceptableMlKemKeyUse(name, false, usagesSet);
+ try {
+ keyObject = createPrivateKey({
+ key: keyData,
+ format: 'der',
+ type: 'pkcs8',
+ });
+ } catch (err) {
+ throw lazyDOMException(
+ 'Invalid keyData', { name: 'DataError', cause: err });
+ }
+ break;
+ }
+ case 'raw-public':
+ case 'raw-seed': {
+ const isPublic = format === 'raw-public';
+ verifyAcceptableMlKemKeyUse(name, isPublic, usagesSet);
+
+ try {
+ keyObject = createMlKemRawKey(name, keyData, isPublic);
+ } catch (err) {
+ throw lazyDOMException('Invalid keyData', { name: 'DataError', cause: err });
+ }
+ break;
+ }
+ default:
+ return undefined;
+ }
+
+ if (keyObject.asymmetricKeyType !== name.toLowerCase()) {
+ throw lazyDOMException('Invalid key type', 'DataError');
+ }
+
+ return new InternalCryptoKey(
+ keyObject,
+ { name },
+ keyUsages,
+ extractable);
+}
+
+function mlKemEncapsulate(encapsulationKey) {
+ if (encapsulationKey[kKeyType] !== 'public') {
+ throw lazyDOMException(`Key must be a public key`, 'InvalidAccessError');
+ }
+
+ const { promise, resolve, reject } = PromiseWithResolvers();
+
+ const job = new KEMEncapsulateJob(
+ kCryptoJobAsync,
+ encapsulationKey[kKeyObject][kHandle],
+ undefined,
+ undefined,
+ undefined);
+
+ job.ondone = (error, result) => {
+ if (error) {
+ reject(lazyDOMException(
+ 'The operation failed for an operation-specific reason',
+ { name: 'OperationError', cause: error }));
+ } else {
+ const { 0: sharedKey, 1: ciphertext } = result;
+ resolve({ sharedKey: sharedKey.buffer, ciphertext: ciphertext.buffer });
+ }
+ };
+ job.run();
+
+ return promise;
+}
+
+function mlKemDecapsulate(decapsulationKey, ciphertext) {
+ if (decapsulationKey[kKeyType] !== 'private') {
+ throw lazyDOMException(`Key must be a private key`, 'InvalidAccessError');
+ }
+
+ const { promise, resolve, reject } = PromiseWithResolvers();
+
+ const job = new KEMDecapsulateJob(
+ kCryptoJobAsync,
+ decapsulationKey[kKeyObject][kHandle],
+ undefined,
+ undefined,
+ undefined,
+ ciphertext);
+
+ job.ondone = (error, result) => {
+ if (error) {
+ reject(lazyDOMException(
+ 'The operation failed for an operation-specific reason',
+ { name: 'OperationError', cause: error }));
+ } else {
+ resolve(result.buffer);
+ }
+ };
+ job.run();
+
+ return promise;
+}
+
+module.exports = {
+ mlKemExportKey,
+ mlKemImportKey,
+ mlKemEncapsulate,
+ mlKemDecapsulate,
+ mlKemGenerateKey,
+};
diff --git a/lib/internal/crypto/pbkdf2.js b/lib/internal/crypto/pbkdf2.js
index 0dc0d25682d2cd..ebdba7334f6556 100644
--- a/lib/internal/crypto/pbkdf2.js
+++ b/lib/internal/crypto/pbkdf2.js
@@ -128,4 +128,5 @@ module.exports = {
pbkdf2,
pbkdf2Sync,
pbkdf2DeriveBits,
+ validatePbkdf2DeriveBitsLength,
};
diff --git a/lib/internal/crypto/rsa.js b/lib/internal/crypto/rsa.js
index bf6c341c5a723d..ecb3759ba48354 100644
--- a/lib/internal/crypto/rsa.js
+++ b/lib/internal/crypto/rsa.js
@@ -50,6 +50,8 @@ const {
PublicKeyObject,
createPublicKey,
createPrivateKey,
+ kAlgorithm,
+ kKeyType,
} = require('internal/crypto/keys');
const {
@@ -95,7 +97,7 @@ function rsaOaepCipher(mode, key, data, algorithm) {
validateRsaOaepAlgorithm(algorithm);
const type = mode === kWebCryptoCipherEncrypt ? 'public' : 'private';
- if (key.type !== type) {
+ if (key[kKeyType] !== type) {
throw lazyDOMException(
'The requested operation is not valid for the provided key',
'InvalidAccessError');
@@ -107,7 +109,7 @@ function rsaOaepCipher(mode, key, data, algorithm) {
key[kKeyObject][kHandle],
data,
kKeyVariantRSA_OAEP,
- normalizeHashName(key.algorithm.hash.name),
+ normalizeHashName(key[kAlgorithm].hash.name),
algorithm.label));
}
@@ -161,7 +163,7 @@ async function rsaKeyGenerate(
name,
modulusLength,
publicExponent,
- hash: { name: hash.name },
+ hash,
};
let publicUsages;
@@ -201,7 +203,7 @@ function rsaExportKey(key, format) {
kCryptoJobAsync,
format,
key[kKeyObject][kHandle],
- kRsaVariants[key.algorithm.name]));
+ kRsaVariants[key[kAlgorithm].name]));
}
function rsaImportKey(
@@ -281,7 +283,7 @@ function rsaImportKey(
algorithm.name === 'RSA-PSS' ? normalizeHashName.kContextJwkRsaPss :
normalizeHashName.kContextJwkRsaOaep);
- if (keyData.alg !== expected)
+ if (expected && keyData.alg !== expected)
throw lazyDOMException(
'JWK "alg" does not match the requested algorithm',
'DataError');
@@ -329,16 +331,16 @@ function rsaSignVerify(key, data, { saltLength }, signature) {
const mode = signature === undefined ? kSignJobModeSign : kSignJobModeVerify;
const type = mode === kSignJobModeSign ? 'private' : 'public';
- if (key.type !== type)
+ if (key[kKeyType] !== type)
throw lazyDOMException(`Key must be a ${type} key`, 'InvalidAccessError');
return jobPromise(() => {
- if (key.algorithm.name === 'RSA-PSS') {
+ if (key[kAlgorithm].name === 'RSA-PSS') {
validateInt32(
saltLength,
'algorithm.saltLength',
0,
- MathCeil((key.algorithm.modulusLength - 1) / 8) - getDigestSizeInBytes(key.algorithm.hash.name) - 2);
+ MathCeil((key[kAlgorithm].modulusLength - 1) / 8) - getDigestSizeInBytes(key[kAlgorithm].hash.name) - 2);
}
return new SignJob(
@@ -349,9 +351,9 @@ function rsaSignVerify(key, data, { saltLength }, signature) {
undefined,
undefined,
data,
- normalizeHashName(key.algorithm.hash.name),
+ normalizeHashName(key[kAlgorithm].hash.name),
saltLength,
- key.algorithm.name === 'RSA-PSS' ? RSA_PKCS1_PSS_PADDING : undefined,
+ key[kAlgorithm].name === 'RSA-PSS' ? RSA_PKCS1_PSS_PADDING : undefined,
undefined,
signature);
});
diff --git a/lib/internal/crypto/util.js b/lib/internal/crypto/util.js
index c7e0c31a4cc609..98d638909ef0e3 100644
--- a/lib/internal/crypto/util.js
+++ b/lib/internal/crypto/util.js
@@ -33,6 +33,13 @@ const {
secureHeapUsed: _secureHeapUsed,
getCachedAliases,
getOpenSSLSecLevelCrypto: getOpenSSLSecLevel,
+ EVP_PKEY_ML_DSA_44,
+ EVP_PKEY_ML_DSA_65,
+ EVP_PKEY_ML_DSA_87,
+ EVP_PKEY_ML_KEM_512,
+ EVP_PKEY_ML_KEM_768,
+ EVP_PKEY_ML_KEM_1024,
+ kKeyVariantAES_OCB_128: hasAesOcbMode,
} = internalBinding('crypto');
const { getOptionValue } = require('internal/options');
@@ -168,141 +175,272 @@ const kNamedCurveAliases = {
'P-521': 'secp521r1',
};
-const kSupportedAlgorithms = {
- 'digest': {
- 'SHA-1': null,
- 'SHA-256': null,
- 'SHA-384': null,
- 'SHA-512': null,
+// Algorithm definitions organized by algorithm name
+const kAlgorithmDefinitions = {
+ 'AES-CBC': {
+ 'generateKey': 'AesKeyGenParams',
+ 'exportKey': null,
+ 'importKey': null,
+ 'encrypt': 'AesCbcParams',
+ 'decrypt': 'AesCbcParams',
+ 'get key length': 'AesDerivedKeyParams',
},
- 'generateKey': {
- 'RSASSA-PKCS1-v1_5': 'RsaHashedKeyGenParams',
- 'RSA-PSS': 'RsaHashedKeyGenParams',
- 'RSA-OAEP': 'RsaHashedKeyGenParams',
- 'ECDSA': 'EcKeyGenParams',
- 'ECDH': 'EcKeyGenParams',
- 'AES-CTR': 'AesKeyGenParams',
- 'AES-CBC': 'AesKeyGenParams',
- 'AES-GCM': 'AesKeyGenParams',
- 'AES-KW': 'AesKeyGenParams',
- 'HMAC': 'HmacKeyGenParams',
- 'Ed25519': null,
- 'X25519': null,
+ 'AES-CTR': {
+ 'generateKey': 'AesKeyGenParams',
+ 'exportKey': null,
+ 'importKey': null,
+ 'encrypt': 'AesCtrParams',
+ 'decrypt': 'AesCtrParams',
+ 'get key length': 'AesDerivedKeyParams',
},
- 'exportKey': {
- 'RSASSA-PKCS1-v1_5': null,
- 'RSA-PSS': null,
- 'RSA-OAEP': null,
- 'ECDSA': null,
- 'ECDH': null,
- 'HMAC': null,
- 'AES-CTR': null,
- 'AES-CBC': null,
- 'AES-GCM': null,
- 'AES-KW': null,
- 'Ed25519': null,
- 'X25519': null,
+ 'AES-GCM': {
+ 'generateKey': 'AesKeyGenParams',
+ 'exportKey': null,
+ 'importKey': null,
+ 'encrypt': 'AeadParams',
+ 'decrypt': 'AeadParams',
+ 'get key length': 'AesDerivedKeyParams',
},
- 'sign': {
- 'RSASSA-PKCS1-v1_5': null,
- 'RSA-PSS': 'RsaPssParams',
- 'ECDSA': 'EcdsaParams',
- 'HMAC': null,
- 'Ed25519': null,
+ 'AES-KW': {
+ 'generateKey': 'AesKeyGenParams',
+ 'exportKey': null,
+ 'importKey': null,
+ 'get key length': 'AesDerivedKeyParams',
+ 'wrapKey': null,
+ 'unwrapKey': null,
},
- 'verify': {
- 'RSASSA-PKCS1-v1_5': null,
- 'RSA-PSS': 'RsaPssParams',
- 'ECDSA': 'EcdsaParams',
- 'HMAC': null,
- 'Ed25519': null,
+ 'AES-OCB': {
+ 'generateKey': 'AesKeyGenParams',
+ 'exportKey': null,
+ 'importKey': null,
+ 'encrypt': 'AeadParams',
+ 'decrypt': 'AeadParams',
+ 'get key length': 'AesDerivedKeyParams',
},
- 'importKey': {
- 'RSASSA-PKCS1-v1_5': 'RsaHashedImportParams',
- 'RSA-PSS': 'RsaHashedImportParams',
- 'RSA-OAEP': 'RsaHashedImportParams',
- 'ECDSA': 'EcKeyImportParams',
- 'ECDH': 'EcKeyImportParams',
- 'HMAC': 'HmacImportParams',
- 'HKDF': null,
- 'PBKDF2': null,
- 'AES-CTR': null,
- 'AES-CBC': null,
- 'AES-GCM': null,
- 'AES-KW': null,
- 'Ed25519': null,
- 'X25519': null,
+ 'ChaCha20-Poly1305': {
+ 'generateKey': null,
+ 'exportKey': null,
+ 'importKey': null,
+ 'encrypt': 'AeadParams',
+ 'decrypt': 'AeadParams',
+ 'get key length': null,
},
- 'deriveBits': {
- 'HKDF': 'HkdfParams',
- 'PBKDF2': 'Pbkdf2Params',
- 'ECDH': 'EcdhKeyDeriveParams',
- 'X25519': 'EcdhKeyDeriveParams',
+ 'cSHAKE128': { 'digest': 'CShakeParams' },
+ 'cSHAKE256': { 'digest': 'CShakeParams' },
+ 'ECDH': {
+ 'generateKey': 'EcKeyGenParams',
+ 'exportKey': null,
+ 'importKey': 'EcKeyImportParams',
+ 'deriveBits': 'EcdhKeyDeriveParams',
},
- 'encrypt': {
- 'RSA-OAEP': 'RsaOaepParams',
- 'AES-CBC': 'AesCbcParams',
- 'AES-GCM': 'AesGcmParams',
- 'AES-CTR': 'AesCtrParams',
+ 'ECDSA': {
+ 'generateKey': 'EcKeyGenParams',
+ 'exportKey': null,
+ 'importKey': 'EcKeyImportParams',
+ 'sign': 'EcdsaParams',
+ 'verify': 'EcdsaParams',
},
- 'decrypt': {
- 'RSA-OAEP': 'RsaOaepParams',
- 'AES-CBC': 'AesCbcParams',
- 'AES-GCM': 'AesGcmParams',
- 'AES-CTR': 'AesCtrParams',
+ 'Ed25519': {
+ 'generateKey': null,
+ 'exportKey': null,
+ 'importKey': null,
+ 'sign': null,
+ 'verify': null,
},
- 'get key length': {
- 'AES-CBC': 'AesDerivedKeyParams',
- 'AES-CTR': 'AesDerivedKeyParams',
- 'AES-GCM': 'AesDerivedKeyParams',
- 'AES-KW': 'AesDerivedKeyParams',
- 'HMAC': 'HmacImportParams',
- 'HKDF': null,
- 'PBKDF2': null,
+ 'Ed448': {
+ 'generateKey': null,
+ 'exportKey': null,
+ 'importKey': null,
+ 'sign': 'Ed448Params',
+ 'verify': 'Ed448Params',
},
- 'wrapKey': {
- 'AES-KW': null,
+ 'HKDF': {
+ 'importKey': null,
+ 'deriveBits': 'HkdfParams',
+ 'get key length': null,
},
- 'unwrapKey': {
- 'AES-KW': null,
+ 'HMAC': {
+ 'generateKey': 'HmacKeyGenParams',
+ 'exportKey': null,
+ 'importKey': 'HmacImportParams',
+ 'sign': null,
+ 'verify': null,
+ 'get key length': 'HmacImportParams',
},
-};
-
-const experimentalAlgorithms = ObjectEntries({
- 'X448': {
- generateKey: null,
- importKey: null,
- deriveBits: 'EcdhKeyDeriveParams',
- exportKey: null,
+ 'ML-DSA-44': {
+ 'generateKey': null,
+ 'exportKey': null,
+ 'importKey': null,
+ 'sign': 'ContextParams',
+ 'verify': 'ContextParams',
},
- 'Ed448': {
- generateKey: null,
- sign: 'Ed448Params',
- verify: 'Ed448Params',
- importKey: null,
- exportKey: null,
+ 'ML-DSA-65': {
+ 'generateKey': null,
+ 'exportKey': null,
+ 'importKey': null,
+ 'sign': 'ContextParams',
+ 'verify': 'ContextParams',
},
-});
+ 'ML-DSA-87': {
+ 'generateKey': null,
+ 'exportKey': null,
+ 'importKey': null,
+ 'sign': 'ContextParams',
+ 'verify': 'ContextParams',
+ },
+ 'ML-KEM-512': {
+ 'generateKey': null,
+ 'exportKey': null,
+ 'importKey': null,
+ 'encapsulate': null,
+ 'decapsulate': null,
+ },
+ 'ML-KEM-768': {
+ 'generateKey': null,
+ 'exportKey': null,
+ 'importKey': null,
+ 'encapsulate': null,
+ 'decapsulate': null,
+ },
+ 'ML-KEM-1024': {
+ 'generateKey': null,
+ 'exportKey': null,
+ 'importKey': null,
+ 'encapsulate': null,
+ 'decapsulate': null,
+ },
+ 'PBKDF2': {
+ 'importKey': null,
+ 'deriveBits': 'Pbkdf2Params',
+ 'get key length': null,
+ },
+ 'RSA-OAEP': {
+ 'generateKey': 'RsaHashedKeyGenParams',
+ 'exportKey': null,
+ 'importKey': 'RsaHashedImportParams',
+ 'encrypt': 'RsaOaepParams',
+ 'decrypt': 'RsaOaepParams',
+ },
+ 'RSA-PSS': {
+ 'generateKey': 'RsaHashedKeyGenParams',
+ 'exportKey': null,
+ 'importKey': 'RsaHashedImportParams',
+ 'sign': 'RsaPssParams',
+ 'verify': 'RsaPssParams',
+ },
+ 'RSASSA-PKCS1-v1_5': {
+ 'generateKey': 'RsaHashedKeyGenParams',
+ 'exportKey': null,
+ 'importKey': 'RsaHashedImportParams',
+ 'sign': null,
+ 'verify': null,
+ },
+ 'SHA-1': { 'digest': null },
+ 'SHA-256': { 'digest': null },
+ 'SHA-384': { 'digest': null },
+ 'SHA-512': { 'digest': null },
+ 'SHA3-256': { 'digest': null },
+ 'SHA3-384': { 'digest': null },
+ 'SHA3-512': { 'digest': null },
+ 'X25519': {
+ 'generateKey': null,
+ 'exportKey': null,
+ 'importKey': null,
+ 'deriveBits': 'EcdhKeyDeriveParams',
+ },
+ 'X448': {
+ 'generateKey': null,
+ 'exportKey': null,
+ 'importKey': null,
+ 'deriveBits': 'EcdhKeyDeriveParams',
+ },
+};
+
+// Conditionally supported algorithms
+const conditionalAlgorithms = {
+ 'AES-KW': !process.features.openssl_is_boringssl,
+ 'AES-OCB': !!hasAesOcbMode,
+ 'ChaCha20-Poly1305': !process.features.openssl_is_boringssl ||
+ ArrayPrototypeIncludes(getCiphers(), 'chacha20-poly1305'),
+ 'cSHAKE128': !process.features.openssl_is_boringssl ||
+ ArrayPrototypeIncludes(getHashes(), 'shake128'),
+ 'cSHAKE256': !process.features.openssl_is_boringssl ||
+ ArrayPrototypeIncludes(getHashes(), 'shake256'),
+ 'Ed448': !process.features.openssl_is_boringssl,
+ 'ML-DSA-44': !!EVP_PKEY_ML_DSA_44,
+ 'ML-DSA-65': !!EVP_PKEY_ML_DSA_65,
+ 'ML-DSA-87': !!EVP_PKEY_ML_DSA_87,
+ 'ML-KEM-512': !!EVP_PKEY_ML_KEM_512,
+ 'ML-KEM-768': !!EVP_PKEY_ML_KEM_768,
+ 'ML-KEM-1024': !!EVP_PKEY_ML_KEM_1024,
+ 'SHA3-256': !process.features.openssl_is_boringssl ||
+ ArrayPrototypeIncludes(getHashes(), 'sha3-256'),
+ 'SHA3-384': !process.features.openssl_is_boringssl ||
+ ArrayPrototypeIncludes(getHashes(), 'sha3-384'),
+ 'SHA3-512': !process.features.openssl_is_boringssl ||
+ ArrayPrototypeIncludes(getHashes(), 'sha3-512'),
+ 'X448': !process.features.openssl_is_boringssl,
+};
-for (let i = 0; i < experimentalAlgorithms.length; i++) {
- const name = experimentalAlgorithms[i][0];
- const ops = ObjectEntries(experimentalAlgorithms[i][1]);
- for (let j = 0; j < ops.length; j++) {
- const { 0: op, 1: dict } = ops[j];
- ObjectDefineProperty(kSupportedAlgorithms[op], name, {
- get() {
- emitExperimentalWarning(`The ${name} Web Crypto API algorithm`);
- return dict;
- },
- __proto__: null,
- enumerable: true,
- });
+// Experimental algorithms
+const experimentalAlgorithms = [
+ 'AES-OCB',
+ 'ChaCha20-Poly1305',
+ 'cSHAKE128',
+ 'cSHAKE256',
+ 'Ed448',
+ 'ML-DSA-44',
+ 'ML-DSA-65',
+ 'ML-DSA-87',
+ 'ML-KEM-512',
+ 'ML-KEM-768',
+ 'ML-KEM-1024',
+ 'SHA3-256',
+ 'SHA3-384',
+ 'SHA3-512',
+ 'X448',
+];
+
+// Transform the algorithm definitions into the operation-keyed structure
+function createSupportedAlgorithms(algorithmDefs) {
+ const result = {};
+
+ for (const { 0: algorithmName, 1: operations } of ObjectEntries(algorithmDefs)) {
+ // Skip algorithms that are conditionally not supported
+ if (ObjectPrototypeHasOwnProperty(conditionalAlgorithms, algorithmName) &&
+ !conditionalAlgorithms[algorithmName]) {
+ continue;
+ }
+
+ for (const { 0: operation, 1: dict } of ObjectEntries(operations)) {
+ result[operation] ||= {};
+
+ // Add experimental warnings for experimental algorithms
+ if (ArrayPrototypeIncludes(experimentalAlgorithms, algorithmName)) {
+ ObjectDefineProperty(result[operation], algorithmName, {
+ get() {
+ emitExperimentalWarning(`The ${algorithmName} Web Crypto API algorithm`);
+ return dict;
+ },
+ __proto__: null,
+ enumerable: true,
+ });
+ } else {
+ result[operation][algorithmName] = dict;
+ }
+ }
}
+
+ return result;
}
+const kSupportedAlgorithms = createSupportedAlgorithms(kAlgorithmDefinitions);
+
const simpleAlgorithmDictionaries = {
- AesGcmParams: { iv: 'BufferSource', additionalData: 'BufferSource' },
- RsaHashedKeyGenParams: { hash: 'HashAlgorithmIdentifier' },
+ AeadParams: { iv: 'BufferSource', additionalData: 'BufferSource' },
+ // publicExponent is not strictly a BufferSource but it is a Uint8Array that we normalize
+ // this way
+ RsaHashedKeyGenParams: { hash: 'HashAlgorithmIdentifier', publicExponent: 'BufferSource' },
EcKeyGenParams: {},
HmacKeyGenParams: { hash: 'HashAlgorithmIdentifier' },
RsaPssParams: {},
@@ -314,10 +452,15 @@ const simpleAlgorithmDictionaries = {
info: 'BufferSource',
},
Ed448Params: { context: 'BufferSource' },
+ ContextParams: { context: 'BufferSource' },
Pbkdf2Params: { hash: 'HashAlgorithmIdentifier', salt: 'BufferSource' },
RsaOaepParams: { label: 'BufferSource' },
RsaHashedImportParams: { hash: 'HashAlgorithmIdentifier' },
EcKeyImportParams: {},
+ CShakeParams: {
+ functionName: 'BufferSource',
+ customization: 'BufferSource',
+ },
};
function validateMaxBufferLength(data, name) {
@@ -526,15 +669,30 @@ function getBlockSize(name) {
// Fall through
case 'SHA-512':
return 1024;
+ case 'SHA3-256':
+ // Fall through
+ case 'SHA3-384':
+ // Fall through
+ case 'SHA3-512':
+ // This interaction is not defined for now.
+ // https://github.com/WICG/webcrypto-modern-algos/issues/23
+ throw lazyDOMException('Explicit algorithm length member is required', 'NotSupportedError');
}
}
function getDigestSizeInBytes(name) {
switch (name) {
- case 'SHA-1': return 20;
- case 'SHA-256': return 32;
- case 'SHA-384': return 48;
- case 'SHA-512': return 64;
+ case 'SHA-1':
+ return 20;
+ case 'SHA-256': // Fall through
+ case 'SHA3-256':
+ return 32;
+ case 'SHA-384': // Fall through
+ case 'SHA3-384':
+ return 48;
+ case 'SHA-512': // Fall through
+ case 'SHA3-512':
+ return 64;
}
}
diff --git a/lib/internal/crypto/webcrypto.js b/lib/internal/crypto/webcrypto.js
index 82bdc29f50a4d4..60f9de5fbfcb28 100644
--- a/lib/internal/crypto/webcrypto.js
+++ b/lib/internal/crypto/webcrypto.js
@@ -8,6 +8,8 @@ const {
ReflectApply,
ReflectConstruct,
StringPrototypeRepeat,
+ StringPrototypeSlice,
+ StringPrototypeStartsWith,
SymbolToStringTag,
} = primordials;
@@ -29,8 +31,13 @@ const {
} = require('internal/errors');
const {
+ createPublicKey,
CryptoKey,
importGenericSecretKey,
+ kAlgorithm,
+ kKeyUsages,
+ kExtractable,
+ kKeyType,
} = require('internal/crypto/keys');
const {
@@ -47,6 +54,7 @@ const {
} = require('internal/crypto/util');
const {
+ emitExperimentalWarning,
kEnumerableProperty,
lazyDOMException,
} = require('internal/util');
@@ -147,20 +155,45 @@ async function generateKey(
// Fall through
case 'AES-GCM':
// Fall through
+ case 'AES-OCB':
+ // Fall through
case 'AES-KW':
resultType = 'CryptoKey';
result = await require('internal/crypto/aes')
.aesGenerateKey(algorithm, extractable, keyUsages);
break;
+ case 'ChaCha20-Poly1305':
+ resultType = 'CryptoKey';
+ result = await require('internal/crypto/chacha20_poly1305')
+ .c20pGenerateKey(algorithm, extractable, keyUsages);
+ break;
+ case 'ML-DSA-44':
+ // Fall through
+ case 'ML-DSA-65':
+ // Fall through
+ case 'ML-DSA-87':
+ resultType = 'CryptoKeyPair';
+ result = await require('internal/crypto/ml_dsa')
+ .mlDsaGenerateKey(algorithm, extractable, keyUsages);
+ break;
+ case 'ML-KEM-512':
+ // Fall through
+ case 'ML-KEM-768':
+ // Fall through
+ case 'ML-KEM-1024':
+ resultType = 'CryptoKeyPair';
+ result = await require('internal/crypto/ml_kem')
+ .mlKemGenerateKey(algorithm, extractable, keyUsages);
+ break;
default:
throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
}
if (
(resultType === 'CryptoKey' &&
- (result.type === 'secret' || result.type === 'private') &&
- result.usages.length === 0) ||
- (resultType === 'CryptoKeyPair' && result.privateKey.usages.length === 0)
+ (result[kKeyType] === 'secret' || result[kKeyType] === 'private') &&
+ result[kKeyUsages].length === 0) ||
+ (resultType === 'CryptoKeyPair' && result.privateKey[kKeyUsages].length === 0)
) {
throw lazyDOMException(
'Usages cannot be empty when creating a key.',
@@ -192,12 +225,12 @@ async function deriveBits(algorithm, baseKey, length = null) {
}
algorithm = normalizeAlgorithm(algorithm, 'deriveBits');
- if (!ArrayPrototypeIncludes(baseKey.usages, 'deriveBits')) {
+ if (!ArrayPrototypeIncludes(baseKey[kKeyUsages], 'deriveBits')) {
throw lazyDOMException(
'baseKey does not have deriveBits usage',
'InvalidAccessError');
}
- if (baseKey.algorithm.name !== algorithm.name)
+ if (baseKey[kAlgorithm].name !== algorithm.name)
throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
switch (algorithm.name) {
case 'X25519':
@@ -222,6 +255,7 @@ function getKeyLength({ name, length, hash }) {
case 'AES-CTR':
case 'AES-CBC':
case 'AES-GCM':
+ case 'AES-OCB':
case 'AES-KW':
if (length !== 128 && length !== 192 && length !== 256)
throw lazyDOMException('Invalid key length', 'OperationError');
@@ -240,6 +274,8 @@ function getKeyLength({ name, length, hash }) {
case 'HKDF':
case 'PBKDF2':
return null;
+ case 'ChaCha20-Poly1305':
+ return 256;
}
}
@@ -277,12 +313,12 @@ async function deriveKey(
algorithm = normalizeAlgorithm(algorithm, 'deriveBits');
derivedKeyAlgorithm = normalizeAlgorithm(derivedKeyAlgorithm, 'importKey');
- if (!ArrayPrototypeIncludes(baseKey.usages, 'deriveKey')) {
+ if (!ArrayPrototypeIncludes(baseKey[kKeyUsages], 'deriveKey')) {
throw lazyDOMException(
'baseKey does not have deriveKey usage',
'InvalidAccessError');
}
- if (baseKey.algorithm.name !== algorithm.name)
+ if (baseKey[kAlgorithm].name !== algorithm.name)
throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
const length = getKeyLength(normalizeAlgorithm(arguments[2], 'get key length'));
@@ -311,12 +347,12 @@ async function deriveKey(
return ReflectApply(
importKey,
this,
- ['raw', bits, derivedKeyAlgorithm, extractable, keyUsages],
+ ['raw-secret', bits, derivedKeyAlgorithm, extractable, keyUsages],
);
}
async function exportKeySpki(key) {
- switch (key.algorithm.name) {
+ switch (key[kAlgorithm].name) {
case 'RSASSA-PKCS1-v1_5':
// Fall through
case 'RSA-PSS':
@@ -338,13 +374,27 @@ async function exportKeySpki(key) {
case 'X448':
return require('internal/crypto/cfrg')
.cfrgExportKey(key, kWebCryptoKeyFormatSPKI);
+ case 'ML-DSA-44':
+ // Fall through
+ case 'ML-DSA-65':
+ // Fall through
+ case 'ML-DSA-87':
+ return require('internal/crypto/ml_dsa')
+ .mlDsaExportKey(key, kWebCryptoKeyFormatSPKI);
+ case 'ML-KEM-512':
+ // Fall through
+ case 'ML-KEM-768':
+ // Fall through
+ case 'ML-KEM-1024':
+ return require('internal/crypto/ml_kem')
+ .mlKemExportKey(key, kWebCryptoKeyFormatSPKI);
default:
return undefined;
}
}
async function exportKeyPkcs8(key) {
- switch (key.algorithm.name) {
+ switch (key[kAlgorithm].name) {
case 'RSASSA-PKCS1-v1_5':
// Fall through
case 'RSA-PSS':
@@ -366,13 +416,27 @@ async function exportKeyPkcs8(key) {
case 'X448':
return require('internal/crypto/cfrg')
.cfrgExportKey(key, kWebCryptoKeyFormatPKCS8);
+ case 'ML-DSA-44':
+ // Fall through
+ case 'ML-DSA-65':
+ // Fall through
+ case 'ML-DSA-87':
+ return require('internal/crypto/ml_dsa')
+ .mlDsaExportKey(key, kWebCryptoKeyFormatPKCS8);
+ case 'ML-KEM-512':
+ // Fall through
+ case 'ML-KEM-768':
+ // Fall through
+ case 'ML-KEM-1024':
+ return require('internal/crypto/ml_kem')
+ .mlKemExportKey(key, kWebCryptoKeyFormatPKCS8);
default:
return undefined;
}
}
-async function exportKeyRawPublic(key) {
- switch (key.algorithm.name) {
+async function exportKeyRawPublic(key, format) {
+ switch (key[kAlgorithm].name) {
case 'ECDSA':
// Fall through
case 'ECDH':
@@ -387,13 +451,58 @@ async function exportKeyRawPublic(key) {
case 'X448':
return require('internal/crypto/cfrg')
.cfrgExportKey(key, kWebCryptoKeyFormatRaw);
+ case 'ML-DSA-44':
+ // Fall through
+ case 'ML-DSA-65':
+ // Fall through
+ case 'ML-DSA-87': {
+ // ML-DSA keys don't recognize "raw"
+ if (format !== 'raw-public') {
+ return undefined;
+ }
+ return require('internal/crypto/ml_dsa')
+ .mlDsaExportKey(key, kWebCryptoKeyFormatRaw);
+ }
+ case 'ML-KEM-512':
+ // Fall through
+ case 'ML-KEM-768':
+ // Fall through
+ case 'ML-KEM-1024': {
+ // ML-KEM keys don't recognize "raw"
+ if (format !== 'raw-public') {
+ return undefined;
+ }
+ return require('internal/crypto/ml_kem')
+ .mlKemExportKey(key, kWebCryptoKeyFormatRaw);
+ }
+ default:
+ return undefined;
+ }
+}
+
+async function exportKeyRawSeed(key) {
+ switch (key[kAlgorithm].name) {
+ case 'ML-DSA-44':
+ // Fall through
+ case 'ML-DSA-65':
+ // Fall through
+ case 'ML-DSA-87':
+ return require('internal/crypto/ml_dsa')
+ .mlDsaExportKey(key, kWebCryptoKeyFormatRaw);
+ case 'ML-KEM-512':
+ // Fall through
+ case 'ML-KEM-768':
+ // Fall through
+ case 'ML-KEM-1024':
+ return require('internal/crypto/ml_kem')
+ .mlKemExportKey(key, kWebCryptoKeyFormatRaw);
default:
return undefined;
}
}
-async function exportKeyRawSecret(key) {
- switch (key.algorithm.name) {
+async function exportKeyRawSecret(key, format) {
+ switch (key[kAlgorithm].name) {
case 'AES-CTR':
// Fall through
case 'AES-CBC':
@@ -404,6 +513,13 @@ async function exportKeyRawSecret(key) {
// Fall through
case 'HMAC':
return key[kKeyObject][kHandle].export().buffer;
+ case 'AES-OCB':
+ // Fall through
+ case 'ChaCha20-Poly1305':
+ if (format === 'raw-secret') {
+ return key[kKeyObject][kHandle].export().buffer;
+ }
+ return undefined;
default:
return undefined;
}
@@ -411,25 +527,31 @@ async function exportKeyRawSecret(key) {
async function exportKeyJWK(key) {
const parameters = {
- key_ops: key.usages,
- ext: key.extractable,
+ key_ops: key[kKeyUsages],
+ ext: key[kExtractable],
};
- switch (key.algorithm.name) {
- case 'RSASSA-PKCS1-v1_5':
- parameters.alg = normalizeHashName(
- key.algorithm.hash.name,
+ switch (key[kAlgorithm].name) {
+ case 'RSASSA-PKCS1-v1_5': {
+ const alg = normalizeHashName(
+ key[kAlgorithm].hash.name,
normalizeHashName.kContextJwkRsa);
+ if (alg) parameters.alg = alg;
break;
- case 'RSA-PSS':
- parameters.alg = normalizeHashName(
- key.algorithm.hash.name,
+ }
+ case 'RSA-PSS': {
+ const alg = normalizeHashName(
+ key[kAlgorithm].hash.name,
normalizeHashName.kContextJwkRsaPss);
+ if (alg) parameters.alg = alg;
break;
- case 'RSA-OAEP':
- parameters.alg = normalizeHashName(
- key.algorithm.hash.name,
+ }
+ case 'RSA-OAEP': {
+ const alg = normalizeHashName(
+ key[kAlgorithm].hash.name,
normalizeHashName.kContextJwkRsaOaep);
+ if (alg) parameters.alg = alg;
break;
+ }
case 'ECDSA':
// Fall through
case 'ECDH':
@@ -437,11 +559,17 @@ async function exportKeyJWK(key) {
case 'X25519':
// Fall through
case 'X448':
+ // Fall through
+ case 'ML-DSA-44':
+ // Fall through
+ case 'ML-DSA-65':
+ // Fall through
+ case 'ML-DSA-87':
break;
case 'Ed25519':
// Fall through
case 'Ed448':
- parameters.alg = key.algorithm.name;
+ parameters.alg = key[kAlgorithm].name;
break;
case 'AES-CTR':
// Fall through
@@ -449,15 +577,22 @@ async function exportKeyJWK(key) {
// Fall through
case 'AES-GCM':
// Fall through
+ case 'AES-OCB':
+ // Fall through
case 'AES-KW':
parameters.alg = require('internal/crypto/aes')
- .getAlgorithmName(key.algorithm.name, key.algorithm.length);
+ .getAlgorithmName(key[kAlgorithm].name, key[kAlgorithm].length);
break;
- case 'HMAC':
- parameters.alg = normalizeHashName(
- key.algorithm.hash.name,
+ case 'ChaCha20-Poly1305':
+ parameters.alg = 'C20P';
+ break;
+ case 'HMAC': {
+ const alg = normalizeHashName(
+ key[kAlgorithm].hash.name,
normalizeHashName.kContextJwkHmac);
+ if (alg) parameters.alg = alg;
break;
+ }
default:
return undefined;
}
@@ -481,25 +616,25 @@ async function exportKey(format, key) {
});
try {
- normalizeAlgorithm(key.algorithm, 'exportKey');
+ normalizeAlgorithm(key[kAlgorithm], 'exportKey');
} catch {
throw lazyDOMException(
- `${key.algorithm.name} key export is not supported`, 'NotSupportedError');
+ `${key[kAlgorithm].name} key export is not supported`, 'NotSupportedError');
}
- if (!key.extractable)
+ if (!key[kExtractable])
throw lazyDOMException('key is not extractable', 'InvalidAccessException');
let result;
switch (format) {
case 'spki': {
- if (key.type === 'public') {
+ if (key[kKeyType] === 'public') {
result = await exportKeySpki(key);
}
break;
}
case 'pkcs8': {
- if (key.type === 'private') {
+ if (key[kKeyType] === 'private') {
result = await exportKeyPkcs8(key);
}
break;
@@ -508,15 +643,29 @@ async function exportKey(format, key) {
result = await exportKeyJWK(key);
break;
}
- case 'raw': {
- if (key.type === 'secret') {
- result = await exportKeyRawSecret(key);
- break;
+ case 'raw-secret': {
+ if (key[kKeyType] === 'secret') {
+ result = await exportKeyRawSecret(key, format);
}
-
- if (key.type === 'public') {
- result = await exportKeyRawPublic(key);
- break;
+ break;
+ }
+ case 'raw-public': {
+ if (key[kKeyType] === 'public') {
+ result = await exportKeyRawPublic(key, format);
+ }
+ break;
+ }
+ case 'raw-seed': {
+ if (key[kKeyType] === 'private') {
+ result = await exportKeyRawSeed(key);
+ }
+ break;
+ }
+ case 'raw': {
+ if (key[kKeyType] === 'secret') {
+ result = await exportKeyRawSecret(key, format);
+ } else if (key[kKeyType] === 'public') {
+ result = await exportKeyRawPublic(key, format);
}
break;
}
@@ -524,13 +673,23 @@ async function exportKey(format, key) {
if (!result) {
throw lazyDOMException(
- `Unable to export ${key.algorithm.name} ${key.type} key using ${format} format`,
+ `Unable to export ${key[kAlgorithm].name} ${key[kKeyType]} key using ${format} format`,
'NotSupportedError');
}
return result;
}
+function aliasKeyFormat(format) {
+ switch (format) {
+ case 'raw-public':
+ case 'raw-secret':
+ return 'raw';
+ default:
+ return format;
+ }
+}
+
async function importKey(
format,
keyData,
@@ -572,12 +731,14 @@ async function importKey(
case 'RSA-PSS':
// Fall through
case 'RSA-OAEP':
+ format = aliasKeyFormat(format);
result = require('internal/crypto/rsa')
.rsaImportKey(format, keyData, algorithm, extractable, keyUsages);
break;
case 'ECDSA':
// Fall through
case 'ECDH':
+ format = aliasKeyFormat(format);
result = require('internal/crypto/ec')
.ecImportKey(format, keyData, algorithm, extractable, keyUsages);
break;
@@ -588,10 +749,12 @@ async function importKey(
case 'X25519':
// Fall through
case 'X448':
+ format = aliasKeyFormat(format);
result = require('internal/crypto/cfrg')
.cfrgImportKey(format, keyData, algorithm, extractable, keyUsages);
break;
case 'HMAC':
+ format = aliasKeyFormat(format);
result = require('internal/crypto/mac')
.hmacImportKey(format, keyData, algorithm, extractable, keyUsages);
break;
@@ -602,12 +765,22 @@ async function importKey(
case 'AES-GCM':
// Fall through
case 'AES-KW':
+ // Fall through
+ case 'AES-OCB':
+ if (algorithm.name !== 'AES-OCB') {
+ format = aliasKeyFormat(format);
+ }
result = require('internal/crypto/aes')
.aesImportKey(algorithm, format, keyData, extractable, keyUsages);
break;
+ case 'ChaCha20-Poly1305':
+ result = require('internal/crypto/chacha20_poly1305')
+ .c20pImportKey(algorithm, format, keyData, extractable, keyUsages);
+ break;
case 'HKDF':
// Fall through
case 'PBKDF2':
+ format = aliasKeyFormat(format);
result = importGenericSecretKey(
algorithm,
format,
@@ -615,6 +788,22 @@ async function importKey(
extractable,
keyUsages);
break;
+ case 'ML-DSA-44':
+ // Fall through
+ case 'ML-DSA-65':
+ // Fall through
+ case 'ML-DSA-87':
+ result = require('internal/crypto/ml_dsa')
+ .mlDsaImportKey(format, keyData, algorithm, extractable, keyUsages);
+ break;
+ case 'ML-KEM-512':
+ // Fall through
+ case 'ML-KEM-768':
+ // Fall through
+ case 'ML-KEM-1024':
+ result = require('internal/crypto/ml_kem')
+ .mlKemImportKey(format, keyData, algorithm, extractable, keyUsages);
+ break;
}
if (!result) {
@@ -623,7 +812,7 @@ async function importKey(
'NotSupportedError');
}
- if ((result.type === 'secret' || result.type === 'private') && result.usages.length === 0) {
+ if ((result.type === 'secret' || result.type === 'private') && result[kKeyUsages].length === 0) {
throw lazyDOMException(
`Usages cannot be empty when importing a ${result.type} key.`,
'SyntaxError');
@@ -771,8 +960,8 @@ function signVerify(algorithm, key, data, signature) {
}
algorithm = normalizeAlgorithm(algorithm, usage);
- if (!ArrayPrototypeIncludes(key.usages, usage) ||
- algorithm.name !== key.algorithm.name) {
+ if (!ArrayPrototypeIncludes(key[kKeyUsages], usage) ||
+ algorithm.name !== key[kAlgorithm].name) {
throw lazyDOMException(
`Unable to use this key to ${usage}`,
'InvalidAccessError');
@@ -796,6 +985,13 @@ function signVerify(algorithm, key, data, signature) {
case 'HMAC':
return require('internal/crypto/mac')
.hmacSignVerify(key, data, algorithm, signature);
+ case 'ML-DSA-44':
+ // Fall through
+ case 'ML-DSA-65':
+ // Fall through
+ case 'ML-DSA-87':
+ return require('internal/crypto/ml_dsa')
+ .mlDsaSignVerify(key, data, algorithm, signature);
}
throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
}
@@ -854,8 +1050,8 @@ async function cipherOrWrap(mode, algorithm, key, data, op) {
// in this case. Both Firefox and Chrome throw simple TypeErrors here.
// The key algorithm and cipher algorithm must match, and the
// key must have the proper usage.
- if (key.algorithm.name !== algorithm.name ||
- !ArrayPrototypeIncludes(key.usages, op)) {
+ if (key[kAlgorithm].name !== algorithm.name ||
+ !ArrayPrototypeIncludes(key[kKeyUsages], op)) {
throw lazyDOMException(
'The requested operation is not valid for the provided key',
'InvalidAccessError');
@@ -875,8 +1071,13 @@ async function cipherOrWrap(mode, algorithm, key, data, op) {
case 'AES-CBC':
// Fall through
case 'AES-GCM':
+ // Fall through
+ case 'AES-OCB':
return require('internal/crypto/aes')
.aesCipher(mode, key, data, algorithm);
+ case 'ChaCha20-Poly1305':
+ return require('internal/crypto/chacha20_poly1305')
+ .c20pCipher(mode, key, data, algorithm);
case 'AES-KW':
if (op === 'wrapKey' || op === 'unwrapKey') {
return require('internal/crypto/aes')
@@ -932,6 +1133,255 @@ async function decrypt(algorithm, key, data) {
return cipherOrWrap(kWebCryptoCipherDecrypt, algorithm, key, data, 'decrypt');
}
+// Implements https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-getPublicKey
+async function getPublicKey(key, keyUsages) {
+ emitExperimentalWarning('The getPublicKey Web Crypto API method');
+ if (this !== subtle) throw new ERR_INVALID_THIS('SubtleCrypto');
+
+ webidl ??= require('internal/crypto/webidl');
+ const prefix = "Failed to execute 'getPublicKey' on 'SubtleCrypto'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ key = webidl.converters.CryptoKey(key, {
+ prefix,
+ context: '1st argument',
+ });
+ keyUsages = webidl.converters['sequence'](keyUsages, {
+ prefix,
+ context: '2nd argument',
+ });
+
+ if (key[kKeyType] !== 'private')
+ throw lazyDOMException('key must be a private key',
+ key[kKeyType] === 'secret' ? 'NotSupportedError' : 'InvalidAccessError');
+
+ const keyObject = createPublicKey(key[kKeyObject]);
+
+ return keyObject.toCryptoKey(key[kAlgorithm], true, keyUsages);
+}
+
+async function encapsulateBits(encapsulationAlgorithm, encapsulationKey) {
+ emitExperimentalWarning('The encapsulateBits Web Crypto API method');
+ if (this !== subtle) throw new ERR_INVALID_THIS('SubtleCrypto');
+
+ webidl ??= require('internal/crypto/webidl');
+ const prefix = "Failed to execute 'encapsulateBits' on 'SubtleCrypto'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+ encapsulationAlgorithm = webidl.converters.AlgorithmIdentifier(encapsulationAlgorithm, {
+ prefix,
+ context: '1st argument',
+ });
+ encapsulationKey = webidl.converters.CryptoKey(encapsulationKey, {
+ prefix,
+ context: '2nd argument',
+ });
+
+ const normalizedEncapsulationAlgorithm = normalizeAlgorithm(encapsulationAlgorithm, 'encapsulate');
+
+ if (normalizedEncapsulationAlgorithm.name !== encapsulationKey[kAlgorithm].name) {
+ throw lazyDOMException(
+ 'key algorithm mismatch',
+ 'InvalidAccessError');
+ }
+
+ if (!ArrayPrototypeIncludes(encapsulationKey[kKeyUsages], 'encapsulateBits')) {
+ throw lazyDOMException(
+ 'encapsulationKey does not have encapsulateBits usage',
+ 'InvalidAccessError');
+ }
+
+ switch (encapsulationKey[kAlgorithm].name) {
+ case 'ML-KEM-512':
+ case 'ML-KEM-768':
+ case 'ML-KEM-1024':
+ return require('internal/crypto/ml_kem')
+ .mlKemEncapsulate(encapsulationKey);
+ }
+
+ throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
+}
+
+async function encapsulateKey(encapsulationAlgorithm, encapsulationKey, sharedKeyAlgorithm, extractable, usages) {
+ emitExperimentalWarning('The encapsulateKey Web Crypto API method');
+ if (this !== subtle) throw new ERR_INVALID_THIS('SubtleCrypto');
+
+ webidl ??= require('internal/crypto/webidl');
+ const prefix = "Failed to execute 'encapsulateKey' on 'SubtleCrypto'";
+ webidl.requiredArguments(arguments.length, 5, { prefix });
+ encapsulationAlgorithm = webidl.converters.AlgorithmIdentifier(encapsulationAlgorithm, {
+ prefix,
+ context: '1st argument',
+ });
+ encapsulationKey = webidl.converters.CryptoKey(encapsulationKey, {
+ prefix,
+ context: '2nd argument',
+ });
+ sharedKeyAlgorithm = webidl.converters.AlgorithmIdentifier(sharedKeyAlgorithm, {
+ prefix,
+ context: '3rd argument',
+ });
+ extractable = webidl.converters.boolean(extractable, {
+ prefix,
+ context: '4th argument',
+ });
+ usages = webidl.converters['sequence'](usages, {
+ prefix,
+ context: '5th argument',
+ });
+
+ const normalizedEncapsulationAlgorithm = normalizeAlgorithm(encapsulationAlgorithm, 'encapsulate');
+ const normalizedSharedKeyAlgorithm = normalizeAlgorithm(sharedKeyAlgorithm, 'importKey');
+
+ if (normalizedEncapsulationAlgorithm.name !== encapsulationKey[kAlgorithm].name) {
+ throw lazyDOMException(
+ 'key algorithm mismatch',
+ 'InvalidAccessError');
+ }
+
+ if (!ArrayPrototypeIncludes(encapsulationKey[kKeyUsages], 'encapsulateKey')) {
+ throw lazyDOMException(
+ 'encapsulationKey does not have encapsulateKey usage',
+ 'InvalidAccessError');
+ }
+
+ let encapsulateBits;
+ switch (encapsulationKey[kAlgorithm].name) {
+ case 'ML-KEM-512':
+ case 'ML-KEM-768':
+ case 'ML-KEM-1024':
+ encapsulateBits = await require('internal/crypto/ml_kem')
+ .mlKemEncapsulate(encapsulationKey);
+ break;
+ default:
+ throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
+ }
+
+ const sharedKey = await ReflectApply(
+ importKey,
+ this,
+ ['raw-secret', encapsulateBits.sharedKey, normalizedSharedKeyAlgorithm, extractable, usages],
+ );
+
+ const encapsulatedKey = {
+ ciphertext: encapsulateBits.ciphertext,
+ sharedKey,
+ };
+
+ return encapsulatedKey;
+}
+
+async function decapsulateBits(decapsulationAlgorithm, decapsulationKey, ciphertext) {
+ emitExperimentalWarning('The decapsulateBits Web Crypto API method');
+ if (this !== subtle) throw new ERR_INVALID_THIS('SubtleCrypto');
+
+ webidl ??= require('internal/crypto/webidl');
+ const prefix = "Failed to execute 'decapsulateBits' on 'SubtleCrypto'";
+ webidl.requiredArguments(arguments.length, 3, { prefix });
+ decapsulationAlgorithm = webidl.converters.AlgorithmIdentifier(decapsulationAlgorithm, {
+ prefix,
+ context: '1st argument',
+ });
+ decapsulationKey = webidl.converters.CryptoKey(decapsulationKey, {
+ prefix,
+ context: '2nd argument',
+ });
+ ciphertext = webidl.converters.BufferSource(ciphertext, {
+ prefix,
+ context: '3rd argument',
+ });
+
+ const normalizedDecapsulationAlgorithm = normalizeAlgorithm(decapsulationAlgorithm, 'decapsulate');
+
+ if (normalizedDecapsulationAlgorithm.name !== decapsulationKey[kAlgorithm].name) {
+ throw lazyDOMException(
+ 'key algorithm mismatch',
+ 'InvalidAccessError');
+ }
+
+ if (!ArrayPrototypeIncludes(decapsulationKey[kKeyUsages], 'decapsulateBits')) {
+ throw lazyDOMException(
+ 'decapsulationKey does not have decapsulateBits usage',
+ 'InvalidAccessError');
+ }
+
+ switch (decapsulationKey[kAlgorithm].name) {
+ case 'ML-KEM-512':
+ case 'ML-KEM-768':
+ case 'ML-KEM-1024':
+ return require('internal/crypto/ml_kem')
+ .mlKemDecapsulate(decapsulationKey, ciphertext);
+ }
+
+ throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
+}
+
+async function decapsulateKey(
+ decapsulationAlgorithm, decapsulationKey, ciphertext, sharedKeyAlgorithm, extractable, usages,
+) {
+ emitExperimentalWarning('The decapsulateKey Web Crypto API method');
+ if (this !== subtle) throw new ERR_INVALID_THIS('SubtleCrypto');
+
+ webidl ??= require('internal/crypto/webidl');
+ const prefix = "Failed to execute 'decapsulateKey' on 'SubtleCrypto'";
+ webidl.requiredArguments(arguments.length, 6, { prefix });
+ decapsulationAlgorithm = webidl.converters.AlgorithmIdentifier(decapsulationAlgorithm, {
+ prefix,
+ context: '1st argument',
+ });
+ decapsulationKey = webidl.converters.CryptoKey(decapsulationKey, {
+ prefix,
+ context: '2nd argument',
+ });
+ ciphertext = webidl.converters.BufferSource(ciphertext, {
+ prefix,
+ context: '3rd argument',
+ });
+ sharedKeyAlgorithm = webidl.converters.AlgorithmIdentifier(sharedKeyAlgorithm, {
+ prefix,
+ context: '4th argument',
+ });
+ extractable = webidl.converters.boolean(extractable, {
+ prefix,
+ context: '5th argument',
+ });
+ usages = webidl.converters['sequence'](usages, {
+ prefix,
+ context: '6th argument',
+ });
+
+ const normalizedDecapsulationAlgorithm = normalizeAlgorithm(decapsulationAlgorithm, 'decapsulate');
+ const normalizedSharedKeyAlgorithm = normalizeAlgorithm(sharedKeyAlgorithm, 'importKey');
+
+ if (normalizedDecapsulationAlgorithm.name !== decapsulationKey[kAlgorithm].name) {
+ throw lazyDOMException(
+ 'key algorithm mismatch',
+ 'InvalidAccessError');
+ }
+
+ if (!ArrayPrototypeIncludes(decapsulationKey[kKeyUsages], 'decapsulateKey')) {
+ throw lazyDOMException(
+ 'decapsulationKey does not have decapsulateKey usage',
+ 'InvalidAccessError');
+ }
+
+ let decapsulatedBits;
+ switch (decapsulationKey[kAlgorithm].name) {
+ case 'ML-KEM-512':
+ case 'ML-KEM-768':
+ case 'ML-KEM-1024':
+ decapsulatedBits = await require('internal/crypto/ml_kem')
+ .mlKemDecapsulate(decapsulationKey, ciphertext);
+ break;
+ default:
+ throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
+ }
+
+ return ReflectApply(
+ importKey,
+ this,
+ ['raw-secret', decapsulatedBits, normalizedSharedKeyAlgorithm, extractable, usages],
+ );
+}
+
// The SubtleCrypto and Crypto classes are defined as part of the
// Web Crypto API standard: https://www.w3.org/TR/WebCryptoAPI/
@@ -939,7 +1389,228 @@ class SubtleCrypto {
constructor() {
throw new ERR_ILLEGAL_CONSTRUCTOR();
}
+
+ // Implements https://wicg.github.io/webcrypto-modern-algos/#SubtleCrypto-method-supports
+ static supports(operation, algorithm, lengthOrAdditionalAlgorithm = null) {
+ emitExperimentalWarning('The supports Web Crypto API method');
+ if (this !== SubtleCrypto) throw new ERR_INVALID_THIS('SubtleCrypto constructor');
+ webidl ??= require('internal/crypto/webidl');
+ const prefix = "Failed to execute 'supports' on 'SubtleCrypto'";
+ webidl.requiredArguments(arguments.length, 2, { prefix });
+
+ operation = webidl.converters.DOMString(operation, {
+ prefix,
+ context: '1st argument',
+ });
+ algorithm = webidl.converters.AlgorithmIdentifier(algorithm, {
+ prefix,
+ context: '2nd argument',
+ });
+
+ switch (operation) {
+ case 'decapsulateBits':
+ case 'decapsulateKey':
+ case 'decrypt':
+ case 'deriveBits':
+ case 'deriveKey':
+ case 'digest':
+ case 'encapsulateBits':
+ case 'encapsulateKey':
+ case 'encrypt':
+ case 'exportKey':
+ case 'generateKey':
+ case 'getPublicKey':
+ case 'importKey':
+ case 'sign':
+ case 'unwrapKey':
+ case 'verify':
+ case 'wrapKey':
+ break;
+ default:
+ return false;
+ }
+
+ let length;
+ let additionalAlgorithm;
+ if (operation === 'deriveKey') {
+ additionalAlgorithm = webidl.converters.AlgorithmIdentifier(lengthOrAdditionalAlgorithm, {
+ prefix,
+ context: '3rd argument',
+ });
+
+ if (!check('importKey', additionalAlgorithm)) {
+ return false;
+ }
+
+ try {
+ length = getKeyLength(normalizeAlgorithm(additionalAlgorithm, 'get key length'));
+ } catch {
+ return false;
+ }
+
+ operation = 'deriveBits';
+ } else if (operation === 'wrapKey') {
+ additionalAlgorithm = webidl.converters.AlgorithmIdentifier(lengthOrAdditionalAlgorithm, {
+ prefix,
+ context: '3rd argument',
+ });
+
+ if (!check('exportKey', additionalAlgorithm)) {
+ return false;
+ }
+ } else if (operation === 'unwrapKey') {
+ additionalAlgorithm = webidl.converters.AlgorithmIdentifier(lengthOrAdditionalAlgorithm, {
+ prefix,
+ context: '3rd argument',
+ });
+
+ if (!check('importKey', additionalAlgorithm)) {
+ return false;
+ }
+ } else if (operation === 'deriveBits') {
+ length = lengthOrAdditionalAlgorithm;
+ if (length !== null) {
+ length = webidl.converters['unsigned long'](length, {
+ prefix,
+ context: '3rd argument',
+ });
+ }
+ } else if (operation === 'getPublicKey') {
+ let normalizedAlgorithm;
+ try {
+ normalizedAlgorithm = normalizeAlgorithm(algorithm, 'exportKey');
+ } catch {
+ return false;
+ }
+
+ switch (StringPrototypeSlice(normalizedAlgorithm.name, 0, 2)) {
+ case 'ML': // ML-DSA-*, ML-KEM-*
+ case 'SL': // SLH-DSA-*
+ case 'RS': // RSA-OAEP, RSA-PSS, RSASSA-PKCS1-v1_5
+ case 'EC': // ECDSA, ECDH
+ case 'Ed': // Ed*
+ case 'X2': // X25519
+ case 'X4': // X448
+ return true;
+ default:
+ return false;
+ }
+ } else if (operation === 'encapsulateKey' || operation === 'decapsulateKey') {
+ additionalAlgorithm = webidl.converters.AlgorithmIdentifier(lengthOrAdditionalAlgorithm, {
+ prefix,
+ context: '3rd argument',
+ });
+
+ let normalizedAdditionalAlgorithm;
+ try {
+ normalizedAdditionalAlgorithm = normalizeAlgorithm(additionalAlgorithm, 'importKey');
+ } catch {
+ return false;
+ }
+
+ switch (normalizedAdditionalAlgorithm.name) {
+ case 'AES-OCB':
+ case 'AES-KW':
+ case 'AES-GCM':
+ case 'AES-CTR':
+ case 'AES-CBC':
+ case 'ChaCha20-Poly1305':
+ case 'HKDF':
+ case 'PBKDF2':
+ case 'Argon2i':
+ case 'Argon2d':
+ case 'Argon2id':
+ break;
+ case 'HMAC':
+ case 'KMAC128':
+ case 'KMAC256':
+ if (normalizedAdditionalAlgorithm.length === undefined || normalizedAdditionalAlgorithm.length === 256) {
+ break;
+ }
+ return false;
+ default:
+ return false;
+ }
+ }
+
+ return check(operation, algorithm, length);
+ }
}
+
+function check(op, alg, length) {
+ if (op === 'encapsulateBits' || op === 'encapsulateKey') {
+ op = 'encapsulate';
+ }
+
+ if (op === 'decapsulateBits' || op === 'decapsulateKey') {
+ op = 'decapsulate';
+ }
+
+ let normalizedAlgorithm;
+ try {
+ normalizedAlgorithm = normalizeAlgorithm(alg, op);
+ } catch {
+ if (op === 'wrapKey') {
+ return check('encrypt', alg);
+ }
+
+ if (op === 'unwrapKey') {
+ return check('decrypt', alg);
+ }
+
+ return false;
+ }
+
+ switch (op) {
+ case 'decapsulate':
+ case 'decrypt':
+ case 'digest':
+ case 'encapsulate':
+ case 'encrypt':
+ case 'exportKey':
+ case 'importKey':
+ case 'sign':
+ case 'unwrapKey':
+ case 'verify':
+ case 'wrapKey':
+ return true;
+ case 'deriveBits': {
+ if (normalizedAlgorithm.name === 'HKDF') {
+ try {
+ require('internal/crypto/hkdf').validateHkdfDeriveBitsLength(length);
+ } catch {
+ return false;
+ }
+ }
+
+ if (normalizedAlgorithm.name === 'PBKDF2') {
+ try {
+ require('internal/crypto/pbkdf2').validatePbkdf2DeriveBitsLength(length);
+ } catch {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ case 'generateKey': {
+ if (
+ normalizedAlgorithm.name === 'HMAC' &&
+ normalizedAlgorithm.length === undefined &&
+ StringPrototypeStartsWith(normalizedAlgorithm.hash.name, 'SHA3-')
+ ) {
+ return false;
+ }
+
+ return true;
+ }
+ default: {
+ const assert = require('internal/assert');
+ assert.fail('Unreachable code');
+ }
+ }
+}
+
const subtle = ReflectConstruct(function() {}, [], SubtleCrypto);
class Crypto {
@@ -1083,6 +1754,41 @@ ObjectDefineProperties(
writable: true,
value: unwrapKey,
},
+ getPublicKey: {
+ __proto__: null,
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ value: getPublicKey,
+ },
+ encapsulateBits: {
+ __proto__: null,
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ value: encapsulateBits,
+ },
+ encapsulateKey: {
+ __proto__: null,
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ value: encapsulateKey,
+ },
+ decapsulateBits: {
+ __proto__: null,
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ value: decapsulateBits,
+ },
+ decapsulateKey: {
+ __proto__: null,
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ value: decapsulateKey,
+ },
});
module.exports = {
diff --git a/lib/internal/crypto/webidl.js b/lib/internal/crypto/webidl.js
index cba02279977e4b..1bec09b17437a0 100644
--- a/lib/internal/crypto/webidl.js
+++ b/lib/internal/crypto/webidl.js
@@ -23,6 +23,8 @@ const {
ObjectPrototypeIsPrototypeOf,
SafeArrayIterator,
String,
+ StringPrototypeStartsWith,
+ StringPrototypeToLowerCase,
TypedArrayPrototypeGetBuffer,
TypedArrayPrototypeGetSymbolToStringTag,
} = primordials;
@@ -192,6 +194,16 @@ converters.object = (V, opts) => {
const isNonSharedArrayBuffer = isArrayBuffer;
+function ensureSHA(V, label) {
+ if (
+ typeof V === 'string' ?
+ !StringPrototypeStartsWith(StringPrototypeToLowerCase(V), 'sha') :
+ V.name?.toLowerCase?.().startsWith('sha') === false
+ )
+ throw lazyDOMException(
+ `Only SHA hashes are supported in ${label}`, 'NotSupportedError');
+}
+
converters.Uint8Array = (V, opts = kEmptyObject) => {
if (!ArrayBufferIsView(V) ||
TypedArrayPrototypeGetSymbolToStringTag(V) !== 'Uint8Array') {
@@ -332,6 +344,10 @@ converters.AlgorithmIdentifier = (V, opts) => {
converters.KeyFormat = createEnumConverter('KeyFormat', [
'raw',
+ 'raw-public',
+ 'raw-seed',
+ 'raw-secret',
+ 'raw-private',
'pkcs8',
'spki',
'jwk',
@@ -346,6 +362,10 @@ converters.KeyUsage = createEnumConverter('KeyUsage', [
'deriveBits',
'wrapKey',
'unwrapKey',
+ 'encapsulateBits',
+ 'decapsulateBits',
+ 'encapsulateKey',
+ 'decapsulateKey',
]);
converters['sequence'] = createSequenceConverter(converters.KeyUsage);
@@ -389,6 +409,7 @@ converters.RsaHashedKeyGenParams = createDictionaryConverter(
{
key: 'hash',
converter: converters.HashAlgorithmIdentifier,
+ validator: (V, dict) => ensureSHA(V, 'RsaHashedKeyGenParams'),
required: true,
},
]);
@@ -399,6 +420,7 @@ converters.RsaHashedImportParams = createDictionaryConverter(
{
key: 'hash',
converter: converters.HashAlgorithmIdentifier,
+ validator: (V, dict) => ensureSHA(V, 'RsaHashedImportParams'),
required: true,
},
]);
@@ -445,6 +467,7 @@ converters.HmacKeyGenParams = createDictionaryConverter(
{
key: 'hash',
converter: converters.HashAlgorithmIdentifier,
+ validator: (V, dict) => ensureSHA(V, 'HmacKeyGenParams'),
required: true,
},
{
@@ -464,6 +487,15 @@ function validateHmacKeyAlgorithm(length) {
throw lazyDOMException('Unsupported algorithm.length', 'NotSupportedError');
}
+function validateZeroLength(parameterName) {
+ return (V, dict) => {
+ if (V.byteLength) {
+ throw lazyDOMException(
+ `Non zero-length ${parameterName} is not supported.`, 'NotSupportedError');
+ }
+ };
+}
+
converters.RsaPssParams = createDictionaryConverter(
'RsaPssParams', [
...new SafeArrayIterator(dictAlgorithm),
@@ -490,6 +522,7 @@ converters.EcdsaParams = createDictionaryConverter(
{
key: 'hash',
converter: converters.HashAlgorithmIdentifier,
+ validator: (V, dict) => ensureSHA(V, 'EcdsaParams'),
required: true,
},
]);
@@ -500,6 +533,7 @@ converters.HmacImportParams = createDictionaryConverter(
{
key: 'hash',
converter: converters.HashAlgorithmIdentifier,
+ validator: (V, dict) => ensureSHA(V, 'HmacImportParams'),
required: true,
},
{
@@ -545,6 +579,8 @@ converters.JsonWebKey = createDictionaryConverter(
simpleDomStringKey('dp'),
simpleDomStringKey('dq'),
simpleDomStringKey('qi'),
+ simpleDomStringKey('pub'),
+ simpleDomStringKey('priv'),
{
key: 'oth',
converter: converters['sequence'],
@@ -558,6 +594,7 @@ converters.HkdfParams = createDictionaryConverter(
{
key: 'hash',
converter: converters.HashAlgorithmIdentifier,
+ validator: (V, dict) => ensureSHA(V, 'HkdfParams'),
required: true,
},
{
@@ -572,12 +609,40 @@ converters.HkdfParams = createDictionaryConverter(
},
]);
+converters.CShakeParams = createDictionaryConverter(
+ 'CShakeParams', [
+ ...new SafeArrayIterator(dictAlgorithm),
+ {
+ key: 'length',
+ converter: (V, opts) =>
+ converters['unsigned long'](V, { ...opts, enforceRange: true }),
+ validator: (V, opts) => {
+ // The Web Crypto spec allows for SHAKE output length that are not multiples of
+ // 8. We don't.
+ if (V % 8)
+ throw lazyDOMException('Unsupported CShakeParams length', 'NotSupportedError');
+ },
+ required: true,
+ },
+ {
+ key: 'functionName',
+ converter: converters.BufferSource,
+ validator: validateZeroLength('CShakeParams.functionName'),
+ },
+ {
+ key: 'customization',
+ converter: converters.BufferSource,
+ validator: validateZeroLength('CShakeParams.customization'),
+ },
+ ]);
+
converters.Pbkdf2Params = createDictionaryConverter(
'Pbkdf2Params', [
...new SafeArrayIterator(dictAlgorithm),
{
key: 'hash',
converter: converters.HashAlgorithmIdentifier,
+ validator: (V, dict) => ensureSHA(V, 'Pbkdf2Params'),
required: true,
},
{
@@ -620,13 +685,29 @@ converters.AesCbcParams = createDictionaryConverter(
},
]);
-converters.AesGcmParams = createDictionaryConverter(
- 'AesGcmParams', [
+converters.AeadParams = createDictionaryConverter(
+ 'AeadParams', [
...new SafeArrayIterator(dictAlgorithm),
{
key: 'iv',
converter: converters.BufferSource,
- validator: (V, dict) => validateMaxBufferLength(V, 'algorithm.iv'),
+ validator: (V, dict) => {
+ switch (StringPrototypeToLowerCase(dict.name)) {
+ case 'chacha20-poly1305':
+ validateByteLength(V, 'algorithm.iv', 12);
+ break;
+ case 'aes-gcm':
+ validateMaxBufferLength(V, 'algorithm.iv');
+ break;
+ case 'aes-ocb':
+ if (V.byteLength > 15) {
+ throw lazyDOMException(
+ 'AES-OCB algorithm.iv must be no more than 15 bytes',
+ 'OperationError');
+ }
+ break;
+ }
+ },
required: true,
},
{
@@ -634,10 +715,28 @@ converters.AesGcmParams = createDictionaryConverter(
converter: (V, opts) =>
converters.octet(V, { ...opts, enforceRange: true }),
validator: (V, dict) => {
- if (!ArrayPrototypeIncludes([32, 64, 96, 104, 112, 120, 128], V)) {
- throw lazyDOMException(
- `${V} is not a valid AES-GCM tag length`,
- 'OperationError');
+ switch (StringPrototypeToLowerCase(dict.name)) {
+ case 'chacha20-poly1305':
+ if (V !== 128) {
+ throw lazyDOMException(
+ `${V} is not a valid ChaCha20-Poly1305 tag length`,
+ 'OperationError');
+ }
+ break;
+ case 'aes-gcm':
+ if (!ArrayPrototypeIncludes([32, 64, 96, 104, 112, 120, 128], V)) {
+ throw lazyDOMException(
+ `${V} is not a valid AES-GCM tag length`,
+ 'OperationError');
+ }
+ break;
+ case 'aes-ocb':
+ if (!ArrayPrototypeIncludes([64, 96, 128], V)) {
+ throw lazyDOMException(
+ `${V} is not a valid AES-OCB tag length`,
+ 'OperationError');
+ }
+ break;
}
},
},
@@ -685,29 +784,26 @@ converters.EcdhKeyDeriveParams = createDictionaryConverter(
throw lazyDOMException(
'algorithm.public must be a public key', 'InvalidAccessError');
- if (V.algorithm.name.toUpperCase() !== dict.name.toUpperCase())
+ if (StringPrototypeToLowerCase(V.algorithm.name) !== StringPrototypeToLowerCase(dict.name))
throw lazyDOMException(
- `algorithm.public must be an ${dict.name.toUpperCase()} key`,
+ 'key algorithm mismatch',
'InvalidAccessError');
},
required: true,
},
]);
-converters.Ed448Params = createDictionaryConverter(
- 'Ed448Params', [
- ...new SafeArrayIterator(dictAlgorithm),
- {
- key: 'context',
- converter: converters.BufferSource,
- validator: (V, dict) => {
- if (V.byteLength)
- throw lazyDOMException(
- 'Non zero-length context is not supported.', 'NotSupportedError');
+for (const name of ['Ed448Params', 'ContextParams']) {
+ converters[name] = createDictionaryConverter(
+ name, [
+ ...new SafeArrayIterator(dictAlgorithm),
+ {
+ key: 'context',
+ converter: converters.BufferSource,
+ validator: validateZeroLength(`${name}.context`),
},
- required: false,
- },
- ]);
+ ]);
+}
module.exports = {
converters,
diff --git a/lib/internal/errors.js b/lib/internal/errors.js
index ade2acdc662312..8a6f5b26f5391c 100644
--- a/lib/internal/errors.js
+++ b/lib/internal/errors.js
@@ -1150,6 +1150,7 @@ E('ERR_CONSOLE_WRITABLE_STREAM',
'Console expects a writable stream instance for %s', TypeError);
E('ERR_CONSTRUCT_CALL_REQUIRED', 'Class constructor %s cannot be invoked without `new`', TypeError);
E('ERR_CONTEXT_NOT_INITIALIZED', 'context used is not initialized', Error);
+E('ERR_CRYPTO_ARGON2_NOT_SUPPORTED', 'Argon2 algorithm not supported', Error);
E('ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED',
'Custom engines not supported by this OpenSSL', Error);
E('ERR_CRYPTO_ECDH_INVALID_FORMAT', 'Invalid ECDH format: %s', TypeError);
@@ -1170,6 +1171,7 @@ E('ERR_CRYPTO_INVALID_JWK', 'Invalid JWK data', TypeError);
E('ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE',
'Invalid key object type %s, expected %s.', TypeError);
E('ERR_CRYPTO_INVALID_STATE', 'Invalid state for operation %s', Error);
+E('ERR_CRYPTO_KEM_NOT_SUPPORTED', 'KEM is not supported', Error);
E('ERR_CRYPTO_PBKDF2_ERROR', 'PBKDF2 error', Error);
E('ERR_CRYPTO_SCRYPT_NOT_SUPPORTED', 'Scrypt algorithm not supported', Error);
// Switch to TypeError. The current implementation does not seem right.
diff --git a/lib/internal/http.js b/lib/internal/http.js
index 4f250a2e70a20f..aa3ec354dabf4a 100644
--- a/lib/internal/http.js
+++ b/lib/internal/http.js
@@ -112,7 +112,9 @@ class ProxyConfig {
const { host, hostname, port, protocol, username, password } = new URL(proxyUrl);
this.href = proxyUrl; // Full URL of the proxy server.
this.host = host; // Full host including port, e.g. 'localhost:8080'.
- this.hostname = hostname.replace(/^\[|\]$/g, ''); // Trim off the brackets from IPv6 addresses.
+ // Trim off the brackets from IPv6 addresses. As it's parsed from a valid URL, an opening
+ // "[" Must already have a matching "]" at the end.
+ this.hostname = hostname[0] === '[' ? hostname.slice(1, -1) : hostname;
this.port = port ? NumberParseInt(port, 10) : (protocol === 'https:' ? 443 : 80);
this.protocol = protocol; // Protocol of the proxy server, e.g. 'http:' or 'https:'.
diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js
index 6bf2edd1487d49..4462fa639317f0 100644
--- a/lib/internal/http2/core.js
+++ b/lib/internal/http2/core.js
@@ -760,7 +760,7 @@ const deprecateWeight = deprecateProperty('weight',
// When a ClientHttp2Session is first created, the socket may not yet be
// connected. If request() is called during this time, the actual request
// will be deferred until the socket is ready to go.
-function requestOnConnect(headersList, headersParam, options) {
+function requestOnConnect(headersList, options) {
const session = this[kSession];
// At this point, the stream should have already been destroyed during
@@ -824,7 +824,7 @@ function requestOnConnect(headersList, headersParam, options) {
if (onClientStreamStartChannel.hasSubscribers) {
onClientStreamStartChannel.publish({
stream: this,
- headers: headersParam,
+ headers: this.sentHeaders,
});
}
}
@@ -1888,7 +1888,7 @@ class ClientHttp2Session extends Http2Session {
}
}
- const onConnect = reqAsync.bind(requestOnConnect.bind(stream, headersList, headersParam, options));
+ const onConnect = reqAsync.bind(requestOnConnect.bind(stream, headersList, options));
if (this.connecting) {
if (this[kPendingRequestCalls] !== null) {
this[kPendingRequestCalls].push(onConnect);
@@ -1906,7 +1906,7 @@ class ClientHttp2Session extends Http2Session {
if (onClientStreamCreatedChannel.hasSubscribers) {
onClientStreamCreatedChannel.publish({
stream,
- headers: headersParam,
+ headers: stream.sentHeaders,
});
}
@@ -2541,8 +2541,31 @@ function callStreamClose(stream) {
stream.close();
}
-function processHeaders(oldHeaders, options) {
- assertIsObject(oldHeaders, 'headers');
+function prepareResponseHeaders(stream, headersParam, options) {
+ let headers;
+ let statusCode;
+
+ if (ArrayIsArray(headersParam)) {
+ ({
+ headers,
+ statusCode,
+ } = prepareResponseHeadersArray(headersParam, options));
+ stream[kRawHeaders] = headers;
+ } else {
+ ({
+ headers,
+ statusCode,
+ } = prepareResponseHeadersObject(headersParam, options));
+ stream[kSentHeaders] = headers;
+ }
+
+ const headersList = buildNgHeaderString(headers, assertValidPseudoHeaderResponse);
+
+ return { headers, headersList, statusCode };
+}
+
+function prepareResponseHeadersObject(oldHeaders, options) {
+ assertIsObject(oldHeaders, 'headers', ['Object', 'Array']);
const headers = { __proto__: null };
if (oldHeaders !== null && oldHeaders !== undefined) {
@@ -2563,6 +2586,44 @@ function processHeaders(oldHeaders, options) {
headers[HTTP2_HEADER_DATE] ??= utcDate();
}
+ validatePreparedResponseHeaders(headers, statusCode);
+
+ return {
+ headers,
+ statusCode: headers[HTTP2_HEADER_STATUS],
+ };
+}
+
+function prepareResponseHeadersArray(headers, options) {
+ let statusCode;
+ let isDateSet = false;
+
+ for (let i = 0; i < headers.length; i += 2) {
+ const header = headers[i].toLowerCase();
+ const value = headers[i + 1];
+
+ if (header === HTTP2_HEADER_STATUS) {
+ statusCode = value | 0;
+ } else if (header === HTTP2_HEADER_DATE) {
+ isDateSet = true;
+ }
+ }
+
+ if (!statusCode) {
+ statusCode = HTTP_STATUS_OK;
+ headers.unshift(HTTP2_HEADER_STATUS, statusCode);
+ }
+
+ if (!isDateSet && (options.sendDate == null || options.sendDate)) {
+ headers.push(HTTP2_HEADER_DATE, utcDate());
+ }
+
+ validatePreparedResponseHeaders(headers, statusCode);
+
+ return { headers, statusCode };
+}
+
+function validatePreparedResponseHeaders(headers, statusCode) {
// This is intentionally stricter than the HTTP/1 implementation, which
// allows values between 100 and 999 (inclusive) in order to allow for
// backwards compatibility with non-spec compliant code. With HTTP/2,
@@ -2570,16 +2631,13 @@ function processHeaders(oldHeaders, options) {
// This will have an impact on the compatibility layer for anyone using
// non-standard, non-compliant status codes.
if (statusCode < 200 || statusCode > 599)
- throw new ERR_HTTP2_STATUS_INVALID(headers[HTTP2_HEADER_STATUS]);
+ throw new ERR_HTTP2_STATUS_INVALID(statusCode);
const neverIndex = headers[kSensitiveHeaders];
if (neverIndex !== undefined && !ArrayIsArray(neverIndex))
throw new ERR_INVALID_ARG_VALUE('headers[http2.neverIndex]', neverIndex);
-
- return headers;
}
-
function onFileUnpipe() {
const stream = this.sink[kOwner];
if (stream.ownsFd)
@@ -2882,7 +2940,7 @@ class ServerHttp2Stream extends Http2Stream {
}
// Initiate a response on this Http2Stream
- respond(headers, options) {
+ respond(headersParam, options) {
if (this.destroyed || this.closed)
throw new ERR_HTTP2_INVALID_STREAM();
if (this.headersSent)
@@ -2907,15 +2965,16 @@ class ServerHttp2Stream extends Http2Stream {
state.flags |= STREAM_FLAGS_HAS_TRAILERS;
}
- headers = processHeaders(headers, options);
- const headersList = buildNgHeaderString(headers, assertValidPseudoHeaderResponse);
- this[kSentHeaders] = headers;
+ const {
+ headers,
+ headersList,
+ statusCode,
+ } = prepareResponseHeaders(this, headersParam, options);
state.flags |= STREAM_FLAGS_HEADERS_SENT;
// Close the writable side if the endStream option is set or status
// is one of known codes with no payload, or it's a head request
- const statusCode = headers[HTTP2_HEADER_STATUS] | 0;
if (!!options.endStream ||
statusCode === HTTP_STATUS_NO_CONTENT ||
statusCode === HTTP_STATUS_RESET_CONTENT ||
@@ -2945,7 +3004,7 @@ class ServerHttp2Stream extends Http2Stream {
// regular file, here the fd is passed directly. If the underlying
// mechanism is not able to read from the fd, then the stream will be
// reset with an error code.
- respondWithFD(fd, headers, options) {
+ respondWithFD(fd, headersParam, options) {
if (this.destroyed || this.closed)
throw new ERR_HTTP2_INVALID_STREAM();
if (this.headersSent)
@@ -2982,8 +3041,11 @@ class ServerHttp2Stream extends Http2Stream {
this[kUpdateTimer]();
this.ownsFd = false;
- headers = processHeaders(headers, options);
- const statusCode = headers[HTTP2_HEADER_STATUS] |= 0;
+ const {
+ headers,
+ statusCode,
+ } = prepareResponseHeadersObject(headersParam, options);
+
// Payload/DATA frames are not permitted in these cases
if (statusCode === HTTP_STATUS_NO_CONTENT ||
statusCode === HTTP_STATUS_RESET_CONTENT ||
@@ -3011,7 +3073,7 @@ class ServerHttp2Stream extends Http2Stream {
// giving the user an opportunity to verify the details and set additional
// headers. If statCheck returns false, the operation is aborted and no
// file details are sent.
- respondWithFile(path, headers, options) {
+ respondWithFile(path, headersParam, options) {
if (this.destroyed || this.closed)
throw new ERR_HTTP2_INVALID_STREAM();
if (this.headersSent)
@@ -3042,8 +3104,11 @@ class ServerHttp2Stream extends Http2Stream {
this[kUpdateTimer]();
this.ownsFd = true;
- headers = processHeaders(headers, options);
- const statusCode = headers[HTTP2_HEADER_STATUS] |= 0;
+ const {
+ headers,
+ statusCode,
+ } = prepareResponseHeadersObject(headersParam, options);
+
// Payload/DATA frames are not permitted in these cases
if (statusCode === HTTP_STATUS_NO_CONTENT ||
statusCode === HTTP_STATUS_RESET_CONTENT ||
diff --git a/lib/internal/http2/util.js b/lib/internal/http2/util.js
index 19cbc08f8a9c7d..77e2386c1bf4aa 100644
--- a/lib/internal/http2/util.js
+++ b/lib/internal/http2/util.js
@@ -690,7 +690,6 @@ function prepareRequestHeadersArray(headers, session) {
const headersList = buildNgHeaderString(
rawHeaders,
assertValidPseudoHeader,
- headers[kSensitiveHeaders],
);
return {
@@ -755,14 +754,14 @@ const kNoHeaderFlags = StringFromCharCode(NGHTTP2_NV_FLAG_NONE);
* @returns {[string, number]}
*/
function buildNgHeaderString(arrayOrMap,
- assertValuePseudoHeader = assertValidPseudoHeader,
- sensitiveHeaders = arrayOrMap[kSensitiveHeaders]) {
+ assertValuePseudoHeader = assertValidPseudoHeader) {
let headers = '';
let pseudoHeaders = '';
let count = 0;
const singles = new SafeSet();
- const neverIndex = (sensitiveHeaders || emptyArray).map((v) => v.toLowerCase());
+ const sensitiveHeaders = arrayOrMap[kSensitiveHeaders] || emptyArray;
+ const neverIndex = sensitiveHeaders.map((v) => v.toLowerCase());
function processHeader(key, value) {
key = key.toLowerCase();
diff --git a/lib/internal/inspector/network_undici.js b/lib/internal/inspector/network_undici.js
index 95be848910f3da..b4031eedcc88d1 100644
--- a/lib/internal/inspector/network_undici.js
+++ b/lib/internal/inspector/network_undici.js
@@ -206,6 +206,39 @@ function onClientResponseFinish({ request }) {
});
}
+// TODO: Move Network.webSocketCreated to the actual creation time of the WebSocket.
+// undici:websocket:open fires when the connection is established, but this results
+// in an inaccurate stack trace.
+function onWebSocketOpen({ websocket }) {
+ websocket[kInspectorRequestId] = getNextRequestId();
+ const url = websocket.url.toString();
+ Network.webSocketCreated({
+ requestId: websocket[kInspectorRequestId],
+ url,
+ });
+ // TODO: Use handshake response data from undici diagnostics when available.
+ // https://github.com/nodejs/undici/pull/4396
+ Network.webSocketHandshakeResponseReceived({
+ requestId: websocket[kInspectorRequestId],
+ timestamp: getMonotonicTime(),
+ response: {
+ status: 101,
+ statusText: 'Switching Protocols',
+ headers: {},
+ },
+ });
+}
+
+function onWebSocketClose({ websocket }) {
+ if (typeof websocket[kInspectorRequestId] !== 'string') {
+ return;
+ }
+ Network.webSocketClosed({
+ requestId: websocket[kInspectorRequestId],
+ timestamp: getMonotonicTime(),
+ });
+}
+
function enable() {
dc.subscribe('undici:request:create', onClientRequestStart);
dc.subscribe('undici:request:error', onClientRequestError);
@@ -214,6 +247,8 @@ function enable() {
dc.subscribe('undici:request:bodyChunkSent', onClientRequestBodyChunkSent);
dc.subscribe('undici:request:bodySent', onClientRequestBodySent);
dc.subscribe('undici:request:bodyChunkReceived', onClientRequestBodyChunkReceived);
+ dc.subscribe('undici:websocket:open', onWebSocketOpen);
+ dc.subscribe('undici:websocket:close', onWebSocketClose);
}
function disable() {
@@ -224,6 +259,8 @@ function disable() {
dc.unsubscribe('undici:request:bodyChunkSent', onClientRequestBodyChunkSent);
dc.unsubscribe('undici:request:bodySent', onClientRequestBodySent);
dc.unsubscribe('undici:request:bodyChunkReceived', onClientRequestBodyChunkReceived);
+ dc.unsubscribe('undici:websocket:open', onWebSocketOpen);
+ dc.unsubscribe('undici:websocket:close', onWebSocketClose);
}
module.exports = {
diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js
index bc36fa2e26b8d0..0443838c8a4ba5 100644
--- a/lib/internal/modules/esm/loader.js
+++ b/lib/internal/modules/esm/loader.js
@@ -65,6 +65,8 @@ let debug = require('internal/util/debuglog').debuglog('esm', (fn) => {
debug = fn;
});
+const { isPromise } = require('internal/util/types');
+
/**
* @typedef {import('./hooks.js').HooksProxy} HooksProxy
* @typedef {import('./module_job.js').ModuleJobBase} ModuleJobBase
@@ -471,6 +473,10 @@ class ModuleLoader {
const resolvedImportAttributes = resolveResult.importAttributes ?? importAttributes;
let job = this.loadCache.get(url, resolvedImportAttributes.type);
if (job !== undefined) {
+ // TODO(node:55782): this race may stop happening when the ESM resolution and loading become synchronous.
+ if (!job.module) {
+ assert.fail(getRaceMessage(url, parentURL));
+ }
// This module is being evaluated, which means it's imported in a previous link
// in a cycle.
if (job.module.getStatus() === kEvaluating) {
@@ -537,7 +543,7 @@ class ModuleLoader {
* matching translators.
* @param {ModuleSource} source Source of the module to be translated.
* @param {boolean} isMain Whether the module to be translated is the entry point.
- * @returns {ModuleWrap | Promise}
+ * @returns {ModuleWrap}
*/
#translate(url, format, source, isMain) {
this.validateLoadResult(url, format);
@@ -547,7 +553,9 @@ class ModuleLoader {
throw new ERR_UNKNOWN_MODULE_FORMAT(format, url);
}
- return FunctionPrototypeCall(translator, this, url, source, isMain);
+ const result = FunctionPrototypeCall(translator, this, url, source, isMain);
+ assert(result instanceof ModuleWrap);
+ return result;
}
/**
@@ -586,15 +594,21 @@ class ModuleLoader {
/**
* Load a module and translate it into a ModuleWrap for ordinary imported ESM.
- * This is run asynchronously.
+ * This may be run asynchronously if there are asynchronous module loader hooks registered.
* @param {string} url URL of the module to be translated.
* @param {object} loadContext See {@link load}
* @param {boolean} isMain Whether the module to be translated is the entry point.
- * @returns {Promise}
+ * @returns {Promise|ModuleWrap}
*/
- async loadAndTranslate(url, loadContext, isMain) {
- const { format, source } = await this.load(url, loadContext);
- return this.#translate(url, format, source, isMain);
+ loadAndTranslate(url, loadContext, isMain) {
+ const maybePromise = this.load(url, loadContext);
+ const afterLoad = ({ format, source }) => {
+ return this.#translate(url, format, source, isMain);
+ };
+ if (isPromise(maybePromise)) {
+ return maybePromise.then(afterLoad);
+ }
+ return afterLoad(maybePromise);
}
/**
diff --git a/lib/internal/modules/esm/module_job.js b/lib/internal/modules/esm/module_job.js
index 268d8154457295..a3b36add4fbe6a 100644
--- a/lib/internal/modules/esm/module_job.js
+++ b/lib/internal/modules/esm/module_job.js
@@ -37,6 +37,7 @@ const {
},
} = internalBinding('util');
const { decorateErrorStack, kEmptyObject } = require('internal/util');
+const { isPromise } = require('internal/util/types');
const {
getSourceMapsSupport,
} = require('internal/source_map/source_map_cache');
@@ -138,12 +139,11 @@ class ModuleJob extends ModuleJobBase {
this.#loader = loader;
// Expose the promise to the ModuleWrap directly for linking below.
- if (isForRequireInImportedCJS) {
- this.module = moduleOrModulePromise;
- assert(this.module instanceof ModuleWrap);
- this.modulePromise = PromiseResolve(this.module);
- } else {
+ if (isPromise(moduleOrModulePromise)) {
this.modulePromise = moduleOrModulePromise;
+ } else {
+ this.module = moduleOrModulePromise;
+ this.modulePromise = PromiseResolve(moduleOrModulePromise);
}
if (this.phase === kEvaluationPhase) {
diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js
index b6ac42302a126b..98bdb384269ced 100644
--- a/lib/internal/modules/esm/translators.js
+++ b/lib/internal/modules/esm/translators.js
@@ -494,18 +494,14 @@ translators.set('json', function jsonStrategy(url, source) {
* >} [[Instance]] slot proxy for WebAssembly Module Record
*/
const wasmInstances = new SafeWeakMap();
-translators.set('wasm', async function(url, source) {
+translators.set('wasm', function(url, source) {
assertBufferSource(source, false, 'load');
debug(`Translating WASMModule ${url}`);
let compiled;
try {
- // TODO(joyeecheung): implement a translator that just uses
- // compiled = new WebAssembly.Module(source) to compile it
- // synchronously.
- compiled = await WebAssembly.compile(source, {
- // The ESM Integration auto-enables Wasm JS builtins by default when available.
+ compiled = new WebAssembly.Module(source, {
builtins: ['js-string'],
});
} catch (err) {
diff --git a/lib/internal/net.js b/lib/internal/net.js
index 4e6accb57a4297..d380d8a41982e2 100644
--- a/lib/internal/net.js
+++ b/lib/internal/net.js
@@ -93,8 +93,8 @@ function isLoopback(host) {
return (
hostLower === 'localhost' ||
hostLower.startsWith('127.') ||
- hostLower.startsWith('[::1]') ||
- hostLower.startsWith('[0:0:0:0:0:0:0:1]')
+ hostLower === '[::1]' ||
+ hostLower === '[0:0:0:0:0:0:0:1]'
);
}
diff --git a/lib/internal/options.js b/lib/internal/options.js
index fef0d61d143335..be1dc6a842c526 100644
--- a/lib/internal/options.js
+++ b/lib/internal/options.js
@@ -11,6 +11,7 @@ const {
const {
getCLIOptionsValues,
getCLIOptionsInfo,
+ getOptionsAsFlags,
getEmbedderOptions: getEmbedderOptionsFromBinding,
getEnvOptionsInputType,
getNamespaceOptionsInputType,
@@ -21,6 +22,7 @@ let warnOnAllowUnauthorized = true;
let optionsDict;
let cliInfo;
let embedderOptions;
+let optionsFlags;
// getCLIOptionsValues() would serialize the option values from C++ land.
// It would error if the values are queried before bootstrap is
@@ -34,6 +36,10 @@ function getCLIOptionsInfoFromBinding() {
return cliInfo ??= getCLIOptionsInfo();
}
+function getOptionsAsFlagsFromBinding() {
+ return optionsFlags ??= getOptionsAsFlags();
+}
+
function getEmbedderOptions() {
return embedderOptions ??= getEmbedderOptionsFromBinding();
}
@@ -156,6 +162,7 @@ function getAllowUnauthorized() {
module.exports = {
getCLIOptionsInfo: getCLIOptionsInfoFromBinding,
getOptionValue,
+ getOptionsAsFlagsFromBinding,
getAllowUnauthorized,
getEmbedderOptions,
generateConfigJsonSchema,
diff --git a/lib/internal/test_runner/harness.js b/lib/internal/test_runner/harness.js
index fe5915dec13483..bd4b35f1d64033 100644
--- a/lib/internal/test_runner/harness.js
+++ b/lib/internal/test_runner/harness.js
@@ -26,7 +26,10 @@ const {
reporterScope,
shouldColorizeTestFiles,
setupGlobalSetupTeardownFunctions,
+ parsePreviousRuns,
} = require('internal/test_runner/utils');
+const { PassThrough, compose } = require('stream');
+const { reportReruns } = require('internal/test_runner/reporter/rerun');
const { queueMicrotask } = require('internal/process/task_queues');
const { TIMEOUT_MAX } = require('internal/timers');
const { clearInterval, setInterval } = require('timers');
@@ -69,6 +72,7 @@ function createTestTree(rootTestOptions, globalOptions) {
shouldColorizeTestFiles: shouldColorizeTestFiles(globalOptions.destinations),
teardown: null,
snapshotManager: null,
+ previousRuns: null,
isFilteringByName,
isFilteringByOnly,
async runBootstrap() {
@@ -203,6 +207,25 @@ function collectCoverage(rootTest, coverage) {
return summary;
}
+function setupFailureStateFile(rootTest, globalOptions) {
+ if (!globalOptions.rerunFailuresFilePath) {
+ return;
+ }
+ rootTest.harness.previousRuns = parsePreviousRuns(globalOptions.rerunFailuresFilePath);
+ if (rootTest.harness.previousRuns === null) {
+ rootTest.diagnostic(`Warning: The rerun failures file at ` +
+ `${globalOptions.rerunFailuresFilePath} is not a valid rerun file. ` +
+ 'The test runner will not be able to rerun failed tests.');
+ rootTest.harness.success = false;
+ process.exitCode = kGenericUserError;
+ return;
+ }
+ if (!process.env.NODE_TEST_CONTEXT) {
+ const reporter = reportReruns(rootTest.harness.previousRuns, globalOptions);
+ compose(rootTest.reporter, reporter).pipe(new PassThrough());
+ }
+}
+
function setupProcessState(root, globalOptions) {
const hook = createHook({
__proto__: null,
@@ -230,6 +253,9 @@ function setupProcessState(root, globalOptions) {
const rejectionHandler =
createProcessEventHandler('unhandledRejection', root);
const coverage = configureCoverage(root, globalOptions);
+
+ setupFailureStateFile(root, globalOptions);
+
const exitHandler = async (kill) => {
if (root.subtests.length === 0 && (root.hooks.before.length > 0 || root.hooks.after.length > 0)) {
// Run global before/after hooks in case there are no tests
diff --git a/lib/internal/test_runner/reporter/junit.js b/lib/internal/test_runner/reporter/junit.js
index 0b2efe119fedee..24bbd9ffc3e1cc 100644
--- a/lib/internal/test_runner/reporter/junit.js
+++ b/lib/internal/test_runner/reporter/junit.js
@@ -58,7 +58,7 @@ function isFailure(node) {
}
function isSkipped(node) {
- return (node?.children && ArrayPrototypeSome(node.children, (c) => c.tag === 'skipped')) || node?.attrs?.failures;
+ return (node?.children && ArrayPrototypeSome(node.children, (c) => c.tag === 'skipped')) || node?.attrs?.skipped;
}
module.exports = async function* junitReporter(source) {
diff --git a/lib/internal/test_runner/reporter/rerun.js b/lib/internal/test_runner/reporter/rerun.js
new file mode 100644
index 00000000000000..1862dafc04ea71
--- /dev/null
+++ b/lib/internal/test_runner/reporter/rerun.js
@@ -0,0 +1,40 @@
+'use strict';
+
+const {
+ ArrayPrototypePush,
+ JSONStringify,
+} = primordials;
+const { relative } = require('path');
+const { writeFileSync } = require('fs');
+
+function reportReruns(previousRuns, globalOptions) {
+ return async function reporter(source) {
+ const obj = { __proto__: null };
+ const disambiguator = { __proto__: null };
+
+ for await (const { type, data } of source) {
+ if (type === 'test:pass') {
+ let identifier = `${relative(globalOptions.cwd, data.file)}:${data.line}:${data.column}`;
+ if (disambiguator[identifier] !== undefined) {
+ identifier += `:(${disambiguator[identifier]})`;
+ disambiguator[identifier] += 1;
+ } else {
+ disambiguator[identifier] = 1;
+ }
+ obj[identifier] = {
+ __proto__: null,
+ name: data.name,
+ passed_on_attempt: data.details.passed_on_attempt ?? data.details.attempt,
+ };
+ }
+ }
+
+ ArrayPrototypePush(previousRuns, obj);
+ writeFileSync(globalOptions.rerunFailuresFilePath, JSONStringify(previousRuns, null, 2), 'utf8');
+ };
+};
+
+module.exports = {
+ __proto__: null,
+ reportReruns,
+};
diff --git a/lib/internal/test_runner/runner.js b/lib/internal/test_runner/runner.js
index 958ad1e060fbbe..1340b817a57e5b 100644
--- a/lib/internal/test_runner/runner.js
+++ b/lib/internal/test_runner/runner.js
@@ -35,7 +35,7 @@ const { spawn } = require('child_process');
const { finished } = require('internal/streams/end-of-stream');
const { resolve, sep, isAbsolute } = require('path');
const { DefaultDeserializer, DefaultSerializer } = require('v8');
-const { getOptionValue } = require('internal/options');
+const { getOptionValue, getOptionsAsFlagsFromBinding } = require('internal/options');
const { Interface } = require('internal/readline/interface');
const { deserializeError } = require('internal/error_serdes');
const { Buffer } = require('buffer');
@@ -148,40 +148,45 @@ function getRunArgs(path, { forceExit,
only,
argv: suppliedArgs,
execArgv,
+ rerunFailuresFilePath,
root: { timeout },
cwd }) {
- const argv = ArrayPrototypeFilter(process.execArgv, filterExecArgv);
+ const processNodeOptions = getOptionsAsFlagsFromBinding();
+ const runArgs = ArrayPrototypeFilter(processNodeOptions, filterExecArgv);
if (forceExit === true) {
- ArrayPrototypePush(argv, '--test-force-exit');
+ ArrayPrototypePush(runArgs, '--test-force-exit');
}
if (isUsingInspector()) {
- ArrayPrototypePush(argv, `--inspect-port=${getInspectPort(inspectPort)}`);
+ ArrayPrototypePush(runArgs, `--inspect-port=${getInspectPort(inspectPort)}`);
}
if (testNamePatterns != null) {
- ArrayPrototypeForEach(testNamePatterns, (pattern) => ArrayPrototypePush(argv, `--test-name-pattern=${pattern}`));
+ ArrayPrototypeForEach(testNamePatterns, (pattern) => ArrayPrototypePush(runArgs, `--test-name-pattern=${pattern}`));
}
if (testSkipPatterns != null) {
- ArrayPrototypeForEach(testSkipPatterns, (pattern) => ArrayPrototypePush(argv, `--test-skip-pattern=${pattern}`));
+ ArrayPrototypeForEach(testSkipPatterns, (pattern) => ArrayPrototypePush(runArgs, `--test-skip-pattern=${pattern}`));
}
if (only === true) {
- ArrayPrototypePush(argv, '--test-only');
+ ArrayPrototypePush(runArgs, '--test-only');
}
if (timeout != null) {
- ArrayPrototypePush(argv, `--test-timeout=${timeout}`);
+ ArrayPrototypePush(runArgs, `--test-timeout=${timeout}`);
+ }
+ if (rerunFailuresFilePath) {
+ ArrayPrototypePush(runArgs, `--test-rerun-failures=${rerunFailuresFilePath}`);
}
- ArrayPrototypePushApply(argv, execArgv);
+ ArrayPrototypePushApply(runArgs, execArgv);
if (path === kIsolatedProcessName) {
- ArrayPrototypePush(argv, '--test');
- ArrayPrototypePushApply(argv, ArrayPrototypeSlice(process.argv, 1));
+ ArrayPrototypePush(runArgs, '--test');
+ ArrayPrototypePushApply(runArgs, ArrayPrototypeSlice(process.argv, 1));
} else {
- ArrayPrototypePush(argv, path);
+ ArrayPrototypePush(runArgs, path);
}
- ArrayPrototypePushApply(argv, suppliedArgs);
+ ArrayPrototypePushApply(runArgs, suppliedArgs);
- return argv;
+ return runArgs;
}
const serializer = new DefaultSerializer();
@@ -587,6 +592,7 @@ function run(options = kEmptyObject) {
execArgv = [],
argv = [],
cwd = process.cwd(),
+ rerunFailuresFilePath,
} = options;
if (files != null) {
@@ -619,6 +625,10 @@ function run(options = kEmptyObject) {
);
}
+ if (rerunFailuresFilePath) {
+ validatePath(rerunFailuresFilePath, 'options.rerunFailuresFilePath');
+ }
+
if (shard != null) {
validateObject(shard, 'options.shard');
// Avoid re-evaluating the shard object in case it's a getter
@@ -701,6 +711,7 @@ function run(options = kEmptyObject) {
coverage,
coverageExcludeGlobs,
coverageIncludeGlobs,
+ rerunFailuresFilePath,
lineCoverage: lineCoverage,
branchCoverage: branchCoverage,
functionCoverage: functionCoverage,
@@ -734,6 +745,7 @@ function run(options = kEmptyObject) {
isolation,
argv,
execArgv,
+ rerunFailuresFilePath,
};
if (isolation === 'process') {
diff --git a/lib/internal/test_runner/test.js b/lib/internal/test_runner/test.js
index 7c9eabb292fde4..8e189b62cad817 100644
--- a/lib/internal/test_runner/test.js
+++ b/lib/internal/test_runner/test.js
@@ -71,6 +71,7 @@ const {
} = require('timers');
const { TIMEOUT_MAX } = require('internal/timers');
const { fileURLToPath } = require('internal/url');
+const { relative } = require('path');
const { availableParallelism } = require('os');
const { innerOk } = require('internal/assert/utils');
const { bigint: hrtime } = process.hrtime;
@@ -290,6 +291,10 @@ class TestContext {
return this.#test.passed;
}
+ get attempt() {
+ return this.#test.attempt ?? 0;
+ }
+
diagnostic(message) {
this.#test.diagnostic(message);
}
@@ -537,6 +542,7 @@ class Test extends AsyncResource {
this.childNumber = 0;
this.timeout = kDefaultTimeout;
this.entryFile = entryFile;
+ this.testDisambiguator = new SafeMap();
} else {
const nesting = parent.parent === null ? parent.nesting :
parent.nesting + 1;
@@ -646,6 +652,8 @@ class Test extends AsyncResource {
this.endTime = null;
this.passed = false;
this.error = null;
+ this.attempt = undefined;
+ this.passedAttempt = undefined;
this.message = typeof skip === 'string' ? skip :
typeof todo === 'string' ? todo : null;
this.activeSubtests = 0;
@@ -690,6 +698,23 @@ class Test extends AsyncResource {
this.loc.file = fileURLToPath(this.loc.file);
}
}
+
+ if (this.loc != null && this.root.harness.previousRuns != null) {
+ let testIdentifier = `${relative(this.config.cwd, this.loc.file)}:${this.loc.line}:${this.loc.column}`;
+ const disambiguator = this.root.testDisambiguator.get(testIdentifier);
+ if (disambiguator !== undefined) {
+ testIdentifier += `:(${disambiguator})`;
+ this.root.testDisambiguator.set(testIdentifier, disambiguator + 1);
+ } else {
+ this.root.testDisambiguator.set(testIdentifier, 1);
+ }
+ this.attempt = this.root.harness.previousRuns.length;
+ const previousAttempt = this.root.harness.previousRuns[this.attempt - 1]?.[testIdentifier]?.passed_on_attempt;
+ if (previousAttempt != null) {
+ this.passedAttempt = previousAttempt;
+ this.fn = noop;
+ }
+ }
}
applyFilters() {
@@ -1329,6 +1354,12 @@ class Test extends AsyncResource {
if (!this.passed) {
details.error = this.error;
}
+ if (this.attempt !== undefined) {
+ details.attempt = this.attempt;
+ }
+ if (this.passedAttempt !== undefined) {
+ details.passed_on_attempt = this.passedAttempt;
+ }
return { __proto__: null, details, directive };
}
@@ -1502,6 +1533,8 @@ class Suite extends Test {
}
function getFullName(test) {
+ if (test === test.root) return test.name;
+
let fullName = test.name;
for (let t = test.parent; t !== t.root; t = t.parent) {
diff --git a/lib/internal/test_runner/utils.js b/lib/internal/test_runner/utils.js
index 44789451d18335..dabfccf6c4f4a4 100644
--- a/lib/internal/test_runner/utils.js
+++ b/lib/internal/test_runner/utils.js
@@ -8,6 +8,7 @@ const {
ArrayPrototypePush,
ArrayPrototypeReduce,
ArrayPrototypeSome,
+ JSONParse,
MathFloor,
MathMax,
MathMin,
@@ -28,7 +29,7 @@ const {
const { AsyncResource } = require('async_hooks');
const { relative, sep, resolve } = require('path');
-const { createWriteStream } = require('fs');
+const { createWriteStream, readFileSync } = require('fs');
const { pathToFileURL } = require('internal/url');
const { getOptionValue } = require('internal/options');
const { green, yellow, red, white, shouldColorize } = require('internal/util/colors');
@@ -150,6 +151,20 @@ function shouldColorizeTestFiles(destinations) {
});
}
+function parsePreviousRuns(rerunFailuresFilePath) {
+ let data;
+ try {
+ data = readFileSync(rerunFailuresFilePath, 'utf8');
+ } catch (err) {
+ if (err.code === 'ENOENT') {
+ data = '[]';
+ } else {
+ throw err;
+ }
+ }
+ return JSONParse(data);
+}
+
async function getReportersMap(reporters, destinations) {
return SafePromiseAllReturnArrayLike(reporters, async (name, i) => {
const destination = kBuiltinDestinations.get(destinations[i]) ??
@@ -202,6 +217,7 @@ function parseCommandLine() {
const updateSnapshots = getOptionValue('--test-update-snapshots');
const watch = getOptionValue('--watch');
const timeout = getOptionValue('--test-timeout') || Infinity;
+ const rerunFailuresFilePath = getOptionValue('--test-rerun-failures');
const isChildProcess = process.env.NODE_TEST_CONTEXT === 'child';
const isChildProcessV8 = process.env.NODE_TEST_CONTEXT === 'child-v8';
let globalSetupPath;
@@ -308,9 +324,12 @@ function parseCommandLine() {
validateInteger(functionCoverage, '--test-coverage-functions', 0, 100);
}
+ if (rerunFailuresFilePath) {
+ validatePath(rerunFailuresFilePath, '--test-rerun-failures');
+ }
+
const setup = reporterScope.bind(async (rootReporter) => {
const reportersMap = await getReportersMap(reporters, destinations);
-
for (let i = 0; i < reportersMap.length; i++) {
const { reporter, destination } = reportersMap[i];
compose(rootReporter, reporter).pipe(destination);
@@ -343,6 +362,7 @@ function parseCommandLine() {
timeout,
updateSnapshots,
watch,
+ rerunFailuresFilePath,
};
return globalTestOptions;
@@ -637,4 +657,5 @@ module.exports = {
shouldColorizeTestFiles,
getCoverageReport,
setupGlobalSetupTeardownFunctions,
+ parsePreviousRuns,
};
diff --git a/lib/internal/util/comparisons.js b/lib/internal/util/comparisons.js
index 178c6aceeff7d7..398d6b43494fe6 100644
--- a/lib/internal/util/comparisons.js
+++ b/lib/internal/util/comparisons.js
@@ -135,8 +135,6 @@ const kIsArray = 1;
const kIsSet = 2;
const kIsMap = 3;
-let kKeyObject;
-
// Check if they have the same source and flags
function areSimilarRegExps(a, b) {
return a.source === b.source &&
@@ -395,11 +393,12 @@ function objectComparisonStart(val1, val2, mode, memos) {
return false;
}
} else if (isCryptoKey(val1)) {
- kKeyObject ??= require('internal/crypto/util').kKeyObject;
+ const { kKeyObject } = require('internal/crypto/util');
+ const { kExtractable, kAlgorithm, kKeyUsages } = require('internal/crypto/keys');
if (!isCryptoKey(val2) ||
- val1.extractable !== val2.extractable ||
- !innerDeepEqual(val1.algorithm, val2.algorithm, mode, memos) ||
- !innerDeepEqual(val1.usages, val2.usages, mode, memos) ||
+ val1[kExtractable] !== val2[kExtractable] ||
+ !innerDeepEqual(val1[kAlgorithm], val2[kAlgorithm], mode, memos) ||
+ !innerDeepEqual(val1[kKeyUsages], val2[kKeyUsages], mode, memos) ||
!innerDeepEqual(val1[kKeyObject], val2[kKeyObject], mode, memos)
) {
return false;
diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js
index 78318243e65eca..bc25cfdd3899b6 100644
--- a/lib/internal/util/inspect.js
+++ b/lib/internal/util/inspect.js
@@ -1,6 +1,8 @@
'use strict';
const {
+ AggregateError,
+ AggregateErrorPrototype,
Array,
ArrayBuffer,
ArrayBufferPrototype,
@@ -74,6 +76,8 @@ const {
ObjectSetPrototypeOf,
Promise,
PromisePrototype,
+ RangeError,
+ RangeErrorPrototype,
ReflectApply,
ReflectOwnKeys,
RegExp,
@@ -114,6 +118,8 @@ const {
SymbolPrototypeValueOf,
SymbolToPrimitive,
SymbolToStringTag,
+ TypeError,
+ TypeErrorPrototype,
TypedArray,
TypedArrayPrototype,
TypedArrayPrototypeGetLength,
@@ -244,7 +250,6 @@ const keyStrRegExp = /^[a-zA-Z_][a-zA-Z_0-9]*$/;
const numberRegExp = /^(0|[1-9][0-9]*)$/;
const coreModuleRegExp = /^ {4}at (?:[^/\\(]+ \(|)node:(.+):\d+:\d+\)?$/;
-const nodeModulesRegExp = /[/\\]node_modules[/\\](.+?)(?=[/\\])/g;
const classRegExp = /^(\s+[^(]*?)\s*{/;
// eslint-disable-next-line node-core/no-unescaped-regexp-dot
@@ -636,7 +641,12 @@ const wellKnownPrototypes = new SafeMap()
.set(RegExpPrototype, { name: 'RegExp', constructor: RegExp })
.set(DatePrototype, { name: 'Date', constructor: Date })
.set(DataViewPrototype, { name: 'DataView', constructor: DataView })
+
.set(ErrorPrototype, { name: 'Error', constructor: Error })
+ .set(AggregateErrorPrototype, { name: 'AggregateError', constructor: AggregateError })
+ .set(RangeErrorPrototype, { name: 'RangeError', constructor: RangeError })
+ .set(TypeErrorPrototype, { name: 'TypeError', constructor: TypeError })
+
.set(BooleanPrototype, { name: 'Boolean', constructor: Boolean })
.set(NumberPrototype, { name: 'Number', constructor: Number })
.set(StringPrototype, { name: 'String', constructor: String })
@@ -1412,16 +1422,45 @@ function removeDuplicateErrorKeys(ctx, keys, err, stack) {
function markNodeModules(ctx, line) {
let tempLine = '';
- let nodeModule;
- let pos = 0;
- while ((nodeModule = nodeModulesRegExp.exec(line)) !== null) {
- // '/node_modules/'.length === 14
- tempLine += StringPrototypeSlice(line, pos, nodeModule.index + 14);
- tempLine += ctx.stylize(nodeModule[1], 'module');
- pos = nodeModule.index + nodeModule[0].length;
- }
- if (pos !== 0) {
- line = tempLine + StringPrototypeSlice(line, pos);
+ let lastPos = 0;
+ let searchFrom = 0;
+
+ while (true) {
+ const nodeModulePosition = StringPrototypeIndexOf(line, 'node_modules', searchFrom);
+ if (nodeModulePosition === -1) {
+ break;
+ }
+
+ // Ensure it's a path segment: must have a path separator before and after
+ const separator = line[nodeModulePosition - 1];
+ const after = line[nodeModulePosition + 12]; // 'node_modules'.length === 12
+
+ if ((after !== '/' && after !== '\\') || (separator !== '/' && separator !== '\\')) {
+ // Not a proper segment; continue searching
+ searchFrom = nodeModulePosition + 1;
+ continue;
+ }
+
+ const moduleStart = nodeModulePosition + 13; // Include trailing separator
+
+ // Append up to and including '/node_modules/'
+ tempLine += StringPrototypeSlice(line, lastPos, moduleStart);
+
+ let moduleEnd = StringPrototypeIndexOf(line, separator, moduleStart);
+ if (line[moduleStart] === '@') {
+ // Namespaced modules have an extra slash: @namespace/package
+ moduleEnd = StringPrototypeIndexOf(line, separator, moduleEnd + 1);
+ }
+
+ const nodeModule = StringPrototypeSlice(line, moduleStart, moduleEnd);
+ tempLine += ctx.stylize(nodeModule, 'module');
+
+ lastPos = moduleEnd;
+ searchFrom = moduleEnd;
+ }
+
+ if (lastPos !== 0) {
+ line = tempLine + StringPrototypeSlice(line, lastPos);
}
return line;
}
diff --git a/lib/internal/webstreams/compression.js b/lib/internal/webstreams/compression.js
index b33b7134096c8b..836c02f7341f70 100644
--- a/lib/internal/webstreams/compression.js
+++ b/lib/internal/webstreams/compression.js
@@ -28,6 +28,7 @@ const formatConverter = createEnumConverter('CompressionFormat', [
'deflate',
'deflate-raw',
'gzip',
+ 'brotli',
]);
/**
@@ -40,7 +41,7 @@ class CompressionStream {
#transform;
/**
- * @param {'deflate'|'deflate-raw'|'gzip'} format
+ * @param {'deflate'|'deflate-raw'|'gzip'|'brotli'} format
*/
constructor(format) {
format = formatConverter(format, {
@@ -57,6 +58,9 @@ class CompressionStream {
case 'gzip':
this.#handle = lazyZlib().createGzip();
break;
+ case 'brotli':
+ this.#handle = lazyZlib().createBrotliCompress();
+ break;
}
this.#transform = newReadableWritablePairFromDuplex(this.#handle);
}
@@ -90,7 +94,7 @@ class DecompressionStream {
#transform;
/**
- * @param {'deflate'|'deflate-raw'|'gzip'} format
+ * @param {'deflate'|'deflate-raw'|'gzip'|'brotli'} format
*/
constructor(format) {
format = formatConverter(format, {
@@ -111,6 +115,9 @@ class DecompressionStream {
rejectGarbageAfterEnd: true,
});
break;
+ case 'brotli':
+ this.#handle = lazyZlib().createBrotliDecompress();
+ break;
}
this.#transform = newReadableWritablePairFromDuplex(this.#handle);
diff --git a/node.gyp b/node.gyp
index bcf01a6b1b5634..51863d37ab7e47 100644
--- a/node.gyp
+++ b/node.gyp
@@ -324,7 +324,9 @@
],
'node_crypto_sources': [
'src/crypto/crypto_aes.cc',
+ 'src/crypto/crypto_argon2.cc',
'src/crypto/crypto_bio.cc',
+ 'src/crypto/crypto_chacha20_poly1305.cc',
'src/crypto/crypto_common.cc',
'src/crypto/crypto_dsa.cc',
'src/crypto/crypto_hkdf.cc',
@@ -335,6 +337,7 @@
'src/crypto/crypto_context.cc',
'src/crypto/crypto_ec.cc',
'src/crypto/crypto_ml_dsa.cc',
+ 'src/crypto/crypto_kem.cc',
'src/crypto/crypto_hmac.cc',
'src/crypto/crypto_random.cc',
'src/crypto/crypto_rsa.cc',
@@ -348,6 +351,7 @@
'src/crypto/crypto_scrypt.cc',
'src/crypto/crypto_tls.cc',
'src/crypto/crypto_x509.cc',
+ 'src/crypto/crypto_argon2.h',
'src/crypto/crypto_bio.h',
'src/crypto/crypto_clienthello-inl.h',
'src/crypto/crypto_dh.h',
@@ -973,11 +977,11 @@
'variables': {
'mkssldef_flags': [
# Categories to export.
- '-CAES,BF,BIO,DES,DH,DSA,EC,ECDH,ECDSA,ENGINE,EVP,HMAC,MD4,MD5,'
- 'PSK,RC2,RC4,RSA,SHA,SHA0,SHA1,SHA256,SHA512,SOCK,STDIO,TLSEXT,'
- 'UI,FP_API,TLS1_METHOD,TLS1_1_METHOD,TLS1_2_METHOD,SCRYPT,OCSP,'
- 'NEXTPROTONEG,RMD160,CAST,DEPRECATEDIN_1_1_0,DEPRECATEDIN_1_2_0,'
- 'DEPRECATEDIN_3_0',
+ '-CAES,ARGON2,BF,BIO,DES,DH,DSA,EC,ECDH,ECDSA,ENGINE,EVP,HMAC,'
+ 'MD4,MD5,PSK,RC2,RC4,RSA,SHA,SHA0,SHA1,SHA256,SHA512,SOCK,STDIO,'
+ 'TLSEXT,UI,FP_API,TLS1_METHOD,TLS1_1_METHOD,TLS1_2_METHOD,'
+ 'SCRYPT,OCSP,NEXTPROTONEG,RMD160,CAST,DEPRECATEDIN_1_1_0,'
+ 'DEPRECATEDIN_1_2_0,DEPRECATEDIN_3_0',
# Defines.
'-DWIN32',
# Symbols to filter from the export list.
diff --git a/src/api/environment.cc b/src/api/environment.cc
index 798f35cb5c6148..be2745fb44759a 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -532,8 +532,19 @@ NODE_EXTERN std::unique_ptr GetInspectorParentHandle(
NODE_EXTERN std::unique_ptr GetInspectorParentHandle(
Environment* env, ThreadId thread_id, const char* url, const char* name) {
- CHECK_NOT_NULL(env);
+ if (url == nullptr) url = "";
if (name == nullptr) name = "";
+ std::string_view url_view(url);
+ std::string_view name_view(name);
+ return GetInspectorParentHandle(env, thread_id, url_view, name_view);
+}
+
+NODE_EXTERN std::unique_ptr GetInspectorParentHandle(
+ Environment* env,
+ ThreadId thread_id,
+ std::string_view url,
+ std::string_view name) {
+ CHECK_NOT_NULL(env);
CHECK_NE(thread_id.id, static_cast(-1));
if (!env->should_create_inspector()) {
return nullptr;
diff --git a/src/async_wrap.cc b/src/async_wrap.cc
index 30490b90e77b64..d9b2c76ede38c0 100644
--- a/src/async_wrap.cc
+++ b/src/async_wrap.cc
@@ -107,6 +107,18 @@ void AsyncWrap::EmitPromiseResolve(Environment* env, double async_id) {
env->async_hooks_promise_resolve_function());
}
+void AsyncWrap::EmitTraceAsyncStart() const {
+ if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
+ TRACING_CATEGORY_NODE1(async_hooks))) {
+ tracing::AsyncWrapArgs data(env()->execution_async_id(),
+ get_trigger_async_id());
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(TRACING_CATEGORY_NODE1(async_hooks),
+ provider_names[provider_type()],
+ static_cast(get_async_id()),
+ "data",
+ tracing::CastTracedValue(data));
+ }
+}
void AsyncWrap::EmitTraceEventBefore() {
switch (provider_type()) {
@@ -601,27 +613,7 @@ void AsyncWrap::AsyncReset(Local |