Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion benchmark/cluster/echo.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ if (cluster.isPrimary) {
payload: ['string', 'object'],
sendsPerBroadcast: [1, 10],
serialization: ['json', 'advanced'],
n: [1e5],
n: [1e3],
});

function main({
Expand Down
5 changes: 5 additions & 0 deletions doc/api/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -3254,6 +3254,11 @@ added: v22.1.0
Enable the [module compile cache][] for the Node.js instance. See the documentation of
[module compile cache][] for details.

### `NODE_COMPILE_CACHE_PORTABLE=1`

When set to 1, the [module compile cache][] can be reused across different directory
locations as long as the module layout relative to the cache directory remains the same.

### `NODE_DEBUG=module[,…]`

<!-- YAML
Expand Down
47 changes: 47 additions & 0 deletions doc/api/deprecations.md
Original file line number Diff line number Diff line change
Expand Up @@ -4026,6 +4026,52 @@ The `node:_http_agent`, `node:_http_client`, `node:_http_common`, `node:_http_in
`node:_http_outgoing` and `node:_http_server` modules are deprecated as they should be considered
an internal nodejs implementation rather than a public facing API, use `node:http` instead.

### DEP0200: Closing fs.Dir on garbage collection

<!-- YAML
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/59839
description: Documentation-only deprecation.
-->

Type: Documentation-only

Allowing a [`fs.Dir`][] object to be closed on garbage collection is
deprecated. In the future, doing so might result in a thrown error that will
terminate the process.

Please ensure that all `fs.Dir` objects are explicitly closed using
`Dir.prototype.close()` or `using` keyword:

```mjs
import { opendir } from 'node:fs/promises';

{
await using dir = await opendir('/async/disposable/directory');
} // Closed by dir[Symbol.asyncDispose]()

{
using dir = await opendir('/sync/disposable/directory');
} // Closed by dir[Symbol.dispose]()

{
const dir = await opendir('/unconditionally/iterated/directory');
for await (const entry of dir) {
// process an entry
} // Closed by iterator
}

{
let dir;
try {
dir = await opendir('/legacy/closeable/directory');
} finally {
await dir?.close();
}
}
```

[DEP0142]: #dep0142-repl_builtinlibs
[NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
[RFC 6066]: https://tools.ietf.org/html/rfc6066#section-3
Expand Down Expand Up @@ -4083,6 +4129,7 @@ an internal nodejs implementation rather than a public facing API, use `node:htt
[`ecdh.setPublicKey()`]: crypto.md#ecdhsetpublickeypublickey-encoding
[`emitter.listenerCount(eventName)`]: events.md#emitterlistenercounteventname-listener
[`events.listenerCount(emitter, eventName)`]: events.md#eventslistenercountemitter-eventname
[`fs.Dir`]: fs.md#class-fsdir
[`fs.FileHandle`]: fs.md#class-filehandle
[`fs.access()`]: fs.md#fsaccesspath-mode-callback
[`fs.appendFile()`]: fs.md#fsappendfilepath-data-options-callback
Expand Down
23 changes: 23 additions & 0 deletions doc/api/module.md
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,28 @@ the [`NODE_COMPILE_CACHE=dir`][] environment variable if it's set, or defaults
to `path.join(os.tmpdir(), 'node-compile-cache')` otherwise. To locate the compile cache
directory used by a running Node.js instance, use [`module.getCompileCacheDir()`][].

By default, caches are invalidated when the absolute paths of the modules being
cached are changed. To keep the cache working after moving the
project directory, enable portable compile cache. This allows previously compiled
modules to be reused across different directory locations as long as the layout relative
to the cache directory remains the same. This would be done on a best-effort basis. If
Node.js cannot compute the location of a module relative to the cache directory, the module
will not be cached.

There are two ways to enable the portable mode:

1. Using the portable option in module.enableCompileCache():

```js
// Non-portable cache (default): cache breaks if project is moved
module.enableCompileCache({ path: '/path/to/cache/storage/dir' });

// Portable cache: cache works after the project is moved
module.enableCompileCache({ path: '/path/to/cache/storage/dir', portable: true });
```

2. Setting the environment variable: [`NODE_COMPILE_CACHE_PORTABLE=1`][]

Currently when using the compile cache with [V8 JavaScript code coverage][], the
coverage being collected by V8 may be less precise in functions that are
deserialized from the code cache. It's recommended to turn this off when
Expand Down Expand Up @@ -1789,6 +1811,7 @@ returned object contains the following keys:
[`--import`]: cli.md#--importmodule
[`--require`]: cli.md#-r---require-module
[`NODE_COMPILE_CACHE=dir`]: cli.md#node_compile_cachedir
[`NODE_COMPILE_CACHE_PORTABLE=1`]: cli.md#node_compile_cache_portable1
[`NODE_DISABLE_COMPILE_CACHE=1`]: cli.md#node_disable_compile_cache1
[`NODE_V8_COVERAGE=dir`]: cli.md#node_v8_coveragedir
[`SourceMap`]: #class-modulesourcemap
Expand Down
7 changes: 7 additions & 0 deletions doc/node.1
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,13 @@ Enable the
.Sy module compile cache
for the Node.js instance.
.
.It Ev NODE_COMPILE_CACHE_PORTABLE
When set to '1' or 'true', the
.Sy module compile cache
will be hit as long as the location of the modules relative to the cache directory remain
consistent. This can be used in conjunction with .Ev NODE_COMPILE_CACHE
to enable portable on-disk caching.
.
.It Ev NODE_DEBUG Ar modules...
Comma-separated list of core modules that should print debug information.
.
Expand Down
24 changes: 13 additions & 11 deletions lib/internal/crypto/aes.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ const {
ArrayBufferPrototypeSlice,
ArrayFrom,
ArrayPrototypePush,
PromiseReject,
SafeSet,
TypedArrayPrototypeSlice,
} = primordials;
Expand Down Expand Up @@ -144,7 +143,7 @@ function asyncAesKwCipher(mode, key, data) {
getVariant('AES-KW', key[kAlgorithm].length)));
}

function asyncAesGcmCipher(mode, key, data, algorithm) {
async function asyncAesGcmCipher(mode, key, data, algorithm) {
const { tagLength = 128 } = algorithm;

const tagByteLength = tagLength / 8;
Expand All @@ -160,9 +159,9 @@ function asyncAesGcmCipher(mode, key, data, algorithm) {
// > If *plaintext* has a length less than *tagLength* bits, then `throw`
// > an `OperationError`.
if (tagByteLength > tag.byteLength) {
return PromiseReject(lazyDOMException(
throw lazyDOMException(
'The provided data is too small.',
'OperationError'));
'OperationError');
}

data = slice(data, 0, -tagByteLength);
Expand All @@ -173,7 +172,7 @@ function asyncAesGcmCipher(mode, key, data, algorithm) {
break;
}

return jobPromise(() => new AESCipherJob(
return await jobPromise(() => new AESCipherJob(
kCryptoJobAsync,
mode,
key[kKeyObject][kHandle],
Expand All @@ -184,7 +183,7 @@ function asyncAesGcmCipher(mode, key, data, algorithm) {
algorithm.additionalData));
}

function asyncAesOcbCipher(mode, key, data, algorithm) {
async function asyncAesOcbCipher(mode, key, data, algorithm) {
const { tagLength = 128 } = algorithm;

const tagByteLength = tagLength / 8;
Expand All @@ -197,9 +196,9 @@ function asyncAesOcbCipher(mode, key, data, algorithm) {

// Similar to GCM, OCB requires the tag to be present for decryption
if (tagByteLength > tag.byteLength) {
return PromiseReject(lazyDOMException(
throw lazyDOMException(
'The provided data is too small.',
'OperationError'));
'OperationError');
}

data = slice(data, 0, -tagByteLength);
Expand All @@ -210,7 +209,7 @@ function asyncAesOcbCipher(mode, key, data, algorithm) {
break;
}

return jobPromise(() => new AESCipherJob(
return await jobPromise(() => new AESCipherJob(
kCryptoJobAsync,
mode,
key[kKeyObject][kHandle],
Expand Down Expand Up @@ -245,12 +244,15 @@ async function aesGenerateKey(algorithm, extractable, keyUsages) {
'SyntaxError');
}

const key = await generateKey('aes', { length }).catch((err) => {
let key;
try {
key = await generateKey('aes', { length });
} catch (err) {
throw lazyDOMException(
'The operation failed for an operation-specific reason' +
`[${err.message}]`,
{ name: 'OperationError', cause: err });
});
}

return new InternalCryptoKey(
key,
Expand Down
11 changes: 7 additions & 4 deletions lib/internal/crypto/cfrg.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,14 @@ async function cfrgGenerateKey(algorithm, extractable, keyUsages) {
break;
}

const keyPair = await generateKeyPair(genKeyType).catch((err) => {
let keyPair;
try {
keyPair = await generateKeyPair(genKeyType);
} catch (err) {
throw lazyDOMException(
'The operation failed for an operation-specific reason',
{ name: 'OperationError', cause: err });
});
}

let publicUsages;
let privateUsages;
Expand Down Expand Up @@ -340,14 +343,14 @@ function cfrgImportKey(
extractable);
}

function eddsaSignVerify(key, data, algorithm, signature) {
async function eddsaSignVerify(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(
return await jobPromise(() => new SignJob(
kCryptoJobAsync,
mode,
key[kKeyObject][kHandle],
Expand Down
16 changes: 9 additions & 7 deletions lib/internal/crypto/chacha20_poly1305.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const {
ArrayBufferIsView,
ArrayBufferPrototypeSlice,
ArrayFrom,
PromiseReject,
SafeSet,
TypedArrayPrototypeSlice,
} = primordials;
Expand Down Expand Up @@ -47,17 +46,17 @@ function validateKeyLength(length) {
throw lazyDOMException('Invalid key length', 'DataError');
}

function c20pCipher(mode, key, data, algorithm) {
async 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(
throw lazyDOMException(
'The provided data is too small.',
'OperationError'));
'OperationError');
}

tag = slice(data, -16);
Expand All @@ -69,7 +68,7 @@ function c20pCipher(mode, key, data, algorithm) {
break;
}

return jobPromise(() => new ChaCha20Poly1305CipherJob(
return await jobPromise(() => new ChaCha20Poly1305CipherJob(
kCryptoJobAsync,
mode,
key[kKeyObject][kHandle],
Expand All @@ -91,12 +90,15 @@ async function c20pGenerateKey(algorithm, extractable, keyUsages) {
'SyntaxError');
}

const keyData = await randomBytes(32).catch((err) => {
let keyData;
try {
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),
Expand Down
15 changes: 9 additions & 6 deletions lib/internal/crypto/ec.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,14 @@ async function ecGenerateKey(algorithm, extractable, keyUsages) {
// Fall through
}

const keypair = await generateKeyPair('ec', { namedCurve }).catch((err) => {
let keyPair;
try {
keyPair = await generateKeyPair('ec', { namedCurve });
} catch (err) {
throw lazyDOMException(
'The operation failed for an operation-specific reason',
{ name: 'OperationError', cause: err });
});
}

let publicUsages;
let privateUsages;
Expand All @@ -120,14 +123,14 @@ async function ecGenerateKey(algorithm, extractable, keyUsages) {

const publicKey =
new InternalCryptoKey(
keypair.publicKey,
keyPair.publicKey,
keyAlgorithm,
publicUsages,
true);

const privateKey =
new InternalCryptoKey(
keypair.privateKey,
keyPair.privateKey,
keyAlgorithm,
privateUsages,
extractable);
Expand Down Expand Up @@ -281,7 +284,7 @@ function ecImportKey(
extractable);
}

function ecdsaSignVerify(key, data, { name, hash }, signature) {
async function ecdsaSignVerify(key, data, { name, hash }, signature) {
const mode = signature === undefined ? kSignJobModeSign : kSignJobModeVerify;
const type = mode === kSignJobModeSign ? 'private' : 'public';

Expand All @@ -290,7 +293,7 @@ function ecdsaSignVerify(key, data, { name, hash }, signature) {

const hashname = normalizeHashName(hash.name);

return jobPromise(() => new SignJob(
return await jobPromise(() => new SignJob(
kCryptoJobAsync,
mode,
key[kKeyObject][kHandle],
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/crypto/hash.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ async function asyncDigest(algorithm, data) {
case 'cSHAKE128':
// Fall through
case 'cSHAKE256':
return jobPromise(() => new HashJob(
return await jobPromise(() => new HashJob(
kCryptoJobAsync,
normalizeHashName(algorithm.name),
data,
Expand Down
Loading
Loading