From 4781f8ca29aecb47614934c061700d983b424db6 Mon Sep 17 00:00:00 2001 From: Ilia Choly Date: Wed, 1 Jul 2026 01:09:53 -0400 Subject: [PATCH 1/6] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#75164=20[sinon?= =?UTF-8?q?]=20Add=20restoreObject=20and=20bump=20to=20v22=20by=20@icholy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- types/sinon/index.d.ts | 6 ++++++ types/sinon/package.json | 2 +- types/sinon/sinon-tests.ts | 12 ++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/types/sinon/index.d.ts b/types/sinon/index.d.ts index 10407a80277212..e142b4948ad3ea 100644 --- a/types/sinon/index.d.ts +++ b/types/sinon/index.d.ts @@ -1424,6 +1424,12 @@ declare namespace Sinon { interface SinonApi { expectation: SinonExpectationStatic; + /** + * Restores all methods of an object and returns the restored object. + * Throws an error if the object contains no restorable methods. + */ + restoreObject(object: T): T; + clock: { create(now: number | Date): FakeTimers.Clock; }; diff --git a/types/sinon/package.json b/types/sinon/package.json index 8a96e48933b9ed..0fea666687f6ce 100644 --- a/types/sinon/package.json +++ b/types/sinon/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@types/sinon", - "version": "21.0.9999", + "version": "22.0.9999", "projects": [ "https://sinonjs.org" ], diff --git a/types/sinon/sinon-tests.ts b/types/sinon/sinon-tests.ts index 8bb828e394f566..e8222ead382552 100644 --- a/types/sinon/sinon-tests.ts +++ b/types/sinon/sinon-tests.ts @@ -887,6 +887,18 @@ function testSetFormatter() { sinon.setFormatter((...args) => JSON.stringify(args)); } +function testRestoreObject() { + const obj = { + foo: () => {}, + }; + sinon.spy(obj, "foo"); + const restored = sinon.restoreObject(obj); // $ExpectType { foo: () => void; } + restored.foo(); + + // @ts-expect-error + sinon.restoreObject(undefined); +} + async function testPromises() { const promise = sinon.promise(); await promise.resolve(123); From e3b9382261e3f5261777fad083220faff5cf4fef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Jun 2026 22:12:33 -0700 Subject: [PATCH 2/6] Bump the github-actions group across 1 directory with 4 updates (#75175) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/CI.yml | 2 +- .github/workflows/UpdateCodeowners.yml | 2 +- .github/workflows/format-and-commit.yml | 4 ++-- .github/workflows/pnpm-cache.yml | 2 +- .github/workflows/support-window.yml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index a794e6ed3c05d0..bb07855a9807cf 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -87,7 +87,7 @@ jobs: echo "store=$(pnpm store path)" >> $GITHUB_OUTPUT - name: Restore pnpm cache - uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ${{ steps.pnpm-cache.outputs.store }} key: ${{ runner.os }}-pnpm-store-cache- diff --git a/.github/workflows/UpdateCodeowners.yml b/.github/workflows/UpdateCodeowners.yml index bd5b95796b506d..d6bedb16d24899 100644 --- a/.github/workflows/UpdateCodeowners.yml +++ b/.github/workflows/UpdateCodeowners.yml @@ -32,7 +32,7 @@ jobs: - run: pnpm run update-codeowners - - uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0 + - uses: stefanzweifel/git-auto-commit-action@4a55954c782fc1ea30b9056cd3e7a2b40ca8887d # v7.2.0 with: commit_author: 'typescript-automation[bot] <290192711+typescript-automation[bot]@users.noreply.github.com>' commit_message: '🤖 Update CODEOWNERS' diff --git a/.github/workflows/format-and-commit.yml b/.github/workflows/format-and-commit.yml index 2ca878f62d1993..7271eddf67dbfa 100644 --- a/.github/workflows/format-and-commit.yml +++ b/.github/workflows/format-and-commit.yml @@ -23,7 +23,7 @@ jobs: id: date run: echo "date=$(/bin/date -u "+%Y-%m-%d")" >> $GITHUB_OUTPUT - - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: # dprint caches info about the files in the repo to skip formatting them. # However, since package.json and .dprint.jsonc don't change very often, @@ -39,7 +39,7 @@ jobs: - run: pnpm dprint fmt - - uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0 + - uses: stefanzweifel/git-auto-commit-action@4a55954c782fc1ea30b9056cd3e7a2b40ca8887d # v7.2.0 with: commit_author: 'typescript-automation[bot] <290192711+typescript-automation[bot]@users.noreply.github.com>' commit_message: '🤖 dprint fmt' diff --git a/.github/workflows/pnpm-cache.yml b/.github/workflows/pnpm-cache.yml index ad90ac2f2faeac..f67e22a51b74a0 100644 --- a/.github/workflows/pnpm-cache.yml +++ b/.github/workflows/pnpm-cache.yml @@ -27,7 +27,7 @@ jobs: run: pnpm install - name: Save pnpm cache - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ${{ steps.pnpm-cache.outputs.store }} key: ${{ runner.os }}-pnpm-store-cache-${{ steps.pnpm-cache.outputs.date }} diff --git a/.github/workflows/support-window.yml b/.github/workflows/support-window.yml index 6570130495934d..3248fc8270a70c 100644 --- a/.github/workflows/support-window.yml +++ b/.github/workflows/support-window.yml @@ -43,7 +43,7 @@ jobs: - name: Make SVG diagram run: node --experimental-json-modules scripts/support-window > docs/support-window.svg - - uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0 + - uses: stefanzweifel/git-auto-commit-action@4a55954c782fc1ea30b9056cd3e7a2b40ca8887d # v7.2.0 with: commit_author: 'typescript-automation[bot] <290192711+typescript-automation[bot]@users.noreply.github.com>' commit_message: '🤖 Update support window' From 325c4b94afae49e03e6484dc947ea54ed423c3c0 Mon Sep 17 00:00:00 2001 From: Erwan Jugand <47392755+erwanjugand@users.noreply.github.com> Date: Wed, 1 Jul 2026 08:35:39 +0200 Subject: [PATCH 3/6] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#75173=20[chrom?= =?UTF-8?q?e]=20add=20missing=20'input'=20permission=20for=20ChromeOS=20by?= =?UTF-8?q?=20@erwanjugand?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- types/chrome/index.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/types/chrome/index.d.ts b/types/chrome/index.d.ts index 3c33206965a4e5..2fba292f3cf114 100644 --- a/types/chrome/index.d.ts +++ b/types/chrome/index.d.ts @@ -9182,6 +9182,7 @@ declare namespace chrome { | "identity" | "identity.email" | "idle" + | "input" | "loginState" | "management" | "nativeMessaging" From 6bc88484143451efd0d88aeb8365b925fa0b22fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ky=E2=84=93e=20Hensel?= Date: Wed, 1 Jul 2026 21:46:47 +1200 Subject: [PATCH 4/6] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#75170=20remove?= =?UTF-8?q?=20through2=20by=20@k-yle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- notNeededPackages.json | 4 + types/gulp-util/package.json | 2 +- types/multistream/package.json | 2 +- types/pbf2json/package.json | 2 +- types/through2-concurrent/package.json | 2 +- types/through2-map/package.json | 2 +- types/through2/.npmignore | 6 -- types/through2/index.d.ts | 44 ----------- types/through2/package.json | 32 -------- types/through2/through2-tests.ts | 100 ------------------------- types/through2/tsconfig.json | 19 ----- types/through2/v0/.eslintrc.json | 5 -- types/through2/v0/.npmignore | 5 -- types/through2/v0/index.d.ts | 25 ------- types/through2/v0/package.json | 20 ----- types/through2/v0/through2-tests.ts | 37 --------- types/through2/v0/tsconfig.json | 19 ----- types/vinyl-fs/package.json | 2 +- 18 files changed, 10 insertions(+), 318 deletions(-) delete mode 100644 types/through2/.npmignore delete mode 100644 types/through2/index.d.ts delete mode 100644 types/through2/package.json delete mode 100644 types/through2/through2-tests.ts delete mode 100644 types/through2/tsconfig.json delete mode 100644 types/through2/v0/.eslintrc.json delete mode 100644 types/through2/v0/.npmignore delete mode 100644 types/through2/v0/index.d.ts delete mode 100644 types/through2/v0/package.json delete mode 100644 types/through2/v0/through2-tests.ts delete mode 100644 types/through2/v0/tsconfig.json diff --git a/notNeededPackages.json b/notNeededPackages.json index 66cf5f0f092c59..3a8cd95963d115 100644 --- a/notNeededPackages.json +++ b/notNeededPackages.json @@ -7743,6 +7743,10 @@ "libraryName": "theming", "asOfVersion": "2.0.0" }, + "through2": { + "libraryName": "through2", + "asOfVersion": "5.0.0" + }, "tildify": { "libraryName": "tildify", "asOfVersion": "2.0.0" diff --git a/types/gulp-util/package.json b/types/gulp-util/package.json index 86f7fb5cb3e8d9..936bbd85d7446d 100644 --- a/types/gulp-util/package.json +++ b/types/gulp-util/package.json @@ -7,7 +7,7 @@ ], "dependencies": { "@types/node": "*", - "@types/through2": "*", + "@types/through2": "<5", "@types/vinyl": "*", "chalk": "^2.2.0" }, diff --git a/types/multistream/package.json b/types/multistream/package.json index 285725f7eb20ed..0510f44ae9b255 100644 --- a/types/multistream/package.json +++ b/types/multistream/package.json @@ -11,7 +11,7 @@ "devDependencies": { "@types/multistream": "workspace:.", "@types/through": "*", - "@types/through2": "*" + "@types/through2": "<5" }, "owners": [ { diff --git a/types/pbf2json/package.json b/types/pbf2json/package.json index 10e64d5b8eca61..bcae5f257fc95f 100644 --- a/types/pbf2json/package.json +++ b/types/pbf2json/package.json @@ -10,7 +10,7 @@ }, "devDependencies": { "@types/pbf2json": "workspace:.", - "@types/through2": "*" + "@types/through2": "<5" }, "owners": [ { diff --git a/types/through2-concurrent/package.json b/types/through2-concurrent/package.json index b0ba35d674ed34..4d54aa8b1f57e9 100644 --- a/types/through2-concurrent/package.json +++ b/types/through2-concurrent/package.json @@ -7,7 +7,7 @@ ], "dependencies": { "@types/node": "*", - "@types/through2": "*" + "@types/through2": "<5" }, "devDependencies": { "@types/through2-concurrent": "workspace:." diff --git a/types/through2-map/package.json b/types/through2-map/package.json index f8424143010f07..35cf3412f59d36 100644 --- a/types/through2-map/package.json +++ b/types/through2-map/package.json @@ -7,7 +7,7 @@ ], "dependencies": { "@types/node": "*", - "@types/through2": "*" + "@types/through2": "<5" }, "devDependencies": { "@types/through2-map": "workspace:." diff --git a/types/through2/.npmignore b/types/through2/.npmignore deleted file mode 100644 index 49916246872b73..00000000000000 --- a/types/through2/.npmignore +++ /dev/null @@ -1,6 +0,0 @@ -* -!**/*.d.ts -!**/*.d.cts -!**/*.d.mts -!**/*.d.*.ts -/v0/ diff --git a/types/through2/index.d.ts b/types/through2/index.d.ts deleted file mode 100644 index a97e317b2b5346..00000000000000 --- a/types/through2/index.d.ts +++ /dev/null @@ -1,44 +0,0 @@ -/// - -import stream = require("stream"); - -declare function through2(transform?: through2.TransformFunction, flush?: through2.FlushCallback): stream.Transform; -declare function through2( - opts?: stream.DuplexOptions, - transform?: through2.TransformFunction, - flush?: through2.FlushCallback, -): stream.Transform; - -declare namespace through2 { - interface Through2Constructor extends stream.Transform { - new(opts?: stream.DuplexOptions): stream.Transform; - (opts?: stream.DuplexOptions): stream.Transform; - } - - type TransformCallback = (err?: any, data?: any) => void; - type TransformFunction = ( - this: stream.Transform, - chunk: any, - enc: BufferEncoding, - callback: TransformCallback, - ) => void; - type FlushCallback = (this: stream.Transform, flushCallback: () => void) => void; - - /** - * Convenvience method for creating object streams - */ - function obj(transform?: TransformFunction, flush?: FlushCallback): stream.Transform; - - /** - * Creates a constructor for a custom Transform. This is useful when you - * want to use the same transform logic in multiple instances. - */ - function ctor(transform?: TransformFunction, flush?: FlushCallback): Through2Constructor; - function ctor( - opts?: stream.DuplexOptions, - transform?: TransformFunction, - flush?: FlushCallback, - ): Through2Constructor; -} - -export = through2; diff --git a/types/through2/package.json b/types/through2/package.json deleted file mode 100644 index 9938d111a673bb..00000000000000 --- a/types/through2/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "private": true, - "name": "@types/through2", - "version": "2.0.9999", - "projects": [ - "https://github.com/rvagg/through2" - ], - "dependencies": { - "@types/node": "*" - }, - "devDependencies": { - "@types/through2": "workspace:." - }, - "owners": [ - { - "name": "Bart van der Schoor", - "githubUsername": "Bartvds" - }, - { - "name": "Georgios Valotasios", - "githubUsername": "valotas" - }, - { - "name": "TeamworkGuy2", - "githubUsername": "TeamworkGuy2" - }, - { - "name": "Alorel", - "githubUsername": "Alorel" - } - ] -} diff --git a/types/through2/through2-tests.ts b/types/through2/through2-tests.ts deleted file mode 100644 index eb2b3b7593447a..00000000000000 --- a/types/through2/through2-tests.ts +++ /dev/null @@ -1,100 +0,0 @@ -import stream = require("stream"); -import through2 = require("through2"); - -var rws: stream.Transform; -var Rws: through2.Through2Constructor; - -rws = through2(); - -rws = through2({ - objectMode: true, - allowHalfOpen: true, -}, function(entry: any, enc: string, callback: () => void) { - this.push("foo"); - callback(); -}, () => { -}); - -rws = through2(function(entry: any, enc: string, callback: () => void) { - this.push("foo"); - callback(); -}, () => { -}); - -rws = through2(function(entry, enc, callback) { - this.push(entry, enc); - callback(null, "continue"); -}, () => { -}); - -rws = through2(function(entry: any, enc: string, callback: (error: any, data?: any) => void) { - callback(null, "foo"); -}, (flushCallback: () => void) => { - flushCallback(); -}); - -rws = through2(function(entry: any, enc: string, callback: () => void) { - this.push("foo"); - callback(); -}, (flushCallback) => { - flushCallback(); -}); - -// obj -rws = through2.obj(function(entry: any, enc: string, callback: () => void) { - this.push("foo"); - callback(); -}, () => { -}); - -rws = through2.obj(function(entry, enc, callback) { - var str: string = enc; - this.push("foo", enc); - callback(null, entry); -}); - -rws = through2.obj(function(entry: any, enc: string, callback: (err: any) => void) { - callback("Oups!"); -}, (flashCallback) => { - flashCallback(); -}); - -// ctor -Rws = through2.ctor({ - objectMode: true, - allowHalfOpen: true, -}, function(entry: any, enc: string, callback: () => void) { - this.push("foo"); - callback(); -}, () => { -}); - -rws = Rws(); -rws = new Rws(); -rws = new Rws({ objectMode: true, allowHalfOpen: true }); - -Rws = through2.ctor(function(entry, enc, callback) { - this.push("foo"); - callback(); -}, () => { -}); - -rws = Rws(); -rws = new Rws(); -rws = new Rws({ objectMode: true, allowHalfOpen: true }); - -Rws = through2.ctor(function(entry: any, enc: string, callback: (error: any, data?: any) => void) { - this.emit("data", "more data"); - callback(null, "foo"); -}, (flushCallback) => { - flushCallback(); -}); - -rws = Rws(); -rws = new Rws(); -rws = new Rws({ objectMode: true, allowHalfOpen: true }); - -Rws = through2.ctor(function(entry: any, enc: string, callback: () => void) { - this.push("foo"); - callback(); -}); diff --git a/types/through2/tsconfig.json b/types/through2/tsconfig.json deleted file mode 100644 index a6b532ac42cfa1..00000000000000 --- a/types/through2/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "module": "node16", - "lib": [ - "es6" - ], - "noImplicitAny": true, - "noImplicitThis": true, - "strictNullChecks": true, - "strictFunctionTypes": true, - "types": [], - "noEmit": true, - "forceConsistentCasingInFileNames": true - }, - "files": [ - "index.d.ts", - "through2-tests.ts" - ] -} diff --git a/types/through2/v0/.eslintrc.json b/types/through2/v0/.eslintrc.json deleted file mode 100644 index 5805df8e2413ed..00000000000000 --- a/types/through2/v0/.eslintrc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rules": { - "@definitelytyped/strict-export-declare-modifiers": "off" - } -} diff --git a/types/through2/v0/.npmignore b/types/through2/v0/.npmignore deleted file mode 100644 index 93e307400a5456..00000000000000 --- a/types/through2/v0/.npmignore +++ /dev/null @@ -1,5 +0,0 @@ -* -!**/*.d.ts -!**/*.d.cts -!**/*.d.mts -!**/*.d.*.ts diff --git a/types/through2/v0/index.d.ts b/types/through2/v0/index.d.ts deleted file mode 100644 index 21273dc32fcd88..00000000000000 --- a/types/through2/v0/index.d.ts +++ /dev/null @@ -1,25 +0,0 @@ -/// - -import stream = require("stream"); - -declare function through2( - transform?: (chunk: any, enc: string, callback: () => void) => void, - flush?: () => void, -): NodeJS.ReadWriteStream; - -declare function through2( - opts?: stream.DuplexOptions, - transform?: (chunk: any, enc: string, callback: () => void) => void, - flush?: () => void, -): NodeJS.ReadWriteStream; - -declare namespace through2 { - export function obj( - transform?: (chunk: any, enc: string, callback: () => void) => void, - flush?: () => void, - ): NodeJS.ReadWriteStream; - - export function push(data: any): void; -} - -export = through2; diff --git a/types/through2/v0/package.json b/types/through2/v0/package.json deleted file mode 100644 index 539223df43f245..00000000000000 --- a/types/through2/v0/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "private": true, - "name": "@types/through2", - "version": "0.4.9999", - "projects": [ - "https://github.com/rvagg/through2" - ], - "dependencies": { - "@types/node": "*" - }, - "devDependencies": { - "@types/through2": "workspace:." - }, - "owners": [ - { - "name": "Bart van der Schoor", - "githubUsername": "Bartvds" - } - ] -} diff --git a/types/through2/v0/through2-tests.ts b/types/through2/v0/through2-tests.ts deleted file mode 100644 index 2befb2485badd4..00000000000000 --- a/types/through2/v0/through2-tests.ts +++ /dev/null @@ -1,37 +0,0 @@ -import through2 = require("through2"); - -var rws: NodeJS.ReadWriteStream; - -rws = through2({ - objectMode: true, - allowHalfOpen: true, -}, function(entry: any, enc: string, callback: () => void) { - this.push("foo"); - callback(); -}, () => { -}); - -rws = through2(function(entry: any, enc: string, callback: () => void) { - this.push("foo"); - callback(); -}, () => { -}); - -rws = through2(function(entry: any, enc: string, callback: () => void) { - this.push("foo"); - callback(); -}); - -rws = through2(); - -// obj -rws = through2.obj(function(entry: any, enc: string, callback: () => void) { - this.push("foo"); - callback(); -}, () => { -}); - -rws = through2.obj(function(entry: any, enc: string, callback: () => void) { - this.push("foo"); - callback(); -}); diff --git a/types/through2/v0/tsconfig.json b/types/through2/v0/tsconfig.json deleted file mode 100644 index 8c58b987925eb9..00000000000000 --- a/types/through2/v0/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "module": "node16", - "lib": [ - "es6" - ], - "noImplicitAny": true, - "noImplicitThis": false, - "strictNullChecks": true, - "strictFunctionTypes": true, - "types": [], - "noEmit": true, - "forceConsistentCasingInFileNames": true - }, - "files": [ - "index.d.ts", - "through2-tests.ts" - ] -} diff --git a/types/vinyl-fs/package.json b/types/vinyl-fs/package.json index e348e261904003..cfd61ac5241a31 100644 --- a/types/vinyl-fs/package.json +++ b/types/vinyl-fs/package.json @@ -12,7 +12,7 @@ }, "devDependencies": { "@types/gulp": "*", - "@types/through2": "*", + "@types/through2": "<5", "@types/vinyl-fs": "workspace:." }, "owners": [ From d90d07af49fefc46b73538509efcafde4a3c83af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9?= Date: Wed, 1 Jul 2026 11:04:30 +0100 Subject: [PATCH 5/6] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#75153=20node:?= =?UTF-8?q?=20v26.1=20by=20@Renegade334?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: xcfio <119097812+xcfio@users.noreply.github.com> --- types/node/buffer.d.ts | 89 +++- types/node/crypto.d.ts | 23 +- types/node/diagnostics_channel.d.ts | 240 ++++++++- types/node/dns.d.ts | 2 +- types/node/ffi.d.ts | 486 +++++++++++++++++++ types/node/fs.d.ts | 27 +- types/node/fs/promises.d.ts | 3 + types/node/http.d.ts | 25 + types/node/index.d.ts | 1 + types/node/node-tests.ts | 1 + types/node/node-tests/buffer.ts | 6 + types/node/node-tests/crypto.ts | 7 + types/node/node-tests/diagnostics_channel.ts | 26 +- types/node/node-tests/ffi.ts | 56 +++ types/node/node-tests/fs.ts | 4 +- types/node/node-tests/http.ts | 2 + types/node/node-tests/sqlite.ts | 3 + types/node/node-tests/stream-iter.ts | 66 ++- types/node/node-tests/test.ts | 11 + types/node/node-tests/util.ts | 4 + types/node/node-tests/v8.ts | 16 + types/node/node-tests/worker_threads.ts | 7 + types/node/package.json | 2 +- types/node/process.d.ts | 15 +- types/node/quic.d.ts | 103 +++- types/node/sqlite.d.ts | 55 +++ types/node/stream.d.ts | 32 ++ types/node/stream/iter.d.ts | 150 ++++++ types/node/test.d.ts | 114 ++++- types/node/ts5.6/index.d.ts | 1 + types/node/ts5.7/index.d.ts | 1 + types/node/util.d.ts | 21 +- types/node/v8.d.ts | 86 +++- types/node/worker_threads.d.ts | 15 +- types/readable-stream/index.d.ts | 27 +- 35 files changed, 1648 insertions(+), 79 deletions(-) create mode 100644 types/node/ffi.d.ts create mode 100644 types/node/node-tests/ffi.ts diff --git a/types/node/buffer.d.ts b/types/node/buffer.d.ts index 9fc15f5587b4ca..f7e9a21a254301 100644 --- a/types/node/buffer.d.ts +++ b/types/node/buffer.d.ts @@ -1550,11 +1550,12 @@ declare module "node:buffer" { /** * If `value` is: * - * * a string, `value` is interpreted according to the character encoding in `encoding`. - * * a `Buffer` or [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array), `value` will be used in its entirety. - * To compare a partial `Buffer`, use `buf.subarray`. + * * a string, `value` is interpreted according to the character encoding in + * `encoding`. + * * a `Buffer` or `Uint8Array`, `value` will be used in its entirety. + * To compare a partial `Buffer`, use `buf.subarray`. * * a number, `value` will be interpreted as an unsigned 8-bit integer - * value between `0` and `255`. + * value between `0` and `255`. * * ```js * import { Buffer } from 'node:buffer'; @@ -1582,12 +1583,13 @@ declare module "node:buffer" { * // Prints: 6 * ``` * - * If `value` is not a string, number, or `Buffer`, this method will throw a `TypeError`. If `value` is a number, it will be coerced to a valid byte value, + * If `value` is not a string, number, or `Buffer`, this method will throw a + * `TypeError`. If `value` is a number, it will be coerced to a valid byte value, * an integer between 0 and 255. * * If `byteOffset` is not a number, it will be coerced to a number. If the result * of coercion is `NaN` or `0`, then the entire buffer will be searched. This - * behavior matches [`String.prototype.indexOf()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf). + * behavior matches `String.prototype.indexOf()`. * * ```js * import { Buffer } from 'node:buffer'; @@ -1608,14 +1610,27 @@ declare module "node:buffer" { * ``` * * If `value` is an empty string or empty `Buffer` and `byteOffset` is less - * than `buf.length`, `byteOffset` will be returned. If `value` is empty and`byteOffset` is at least `buf.length`, `buf.length` will be returned. + * than `buf.length`, `byteOffset` will be returned. If `value` is empty and + * `byteOffset` is at least `buf.length`, `buf.length` will be returned. * @since v1.5.0 * @param value What to search for. - * @param [byteOffset=0] Where to begin searching in `buf`. If negative, then offset is calculated from the end of `buf`. - * @param [encoding='utf8'] If `value` is a string, this is the encoding used to determine the binary representation of the string that will be searched for in `buf`. - * @return The index of the first occurrence of `value` in `buf`, or `-1` if `buf` does not contain `value`. - */ - indexOf(value: string | number | Uint8Array, byteOffset?: number, encoding?: BufferEncoding): number; + * @param start Where to begin searching in `buf`. If negative, then + * offset is calculated from the end of `buf`. **Default:** `0`. + * @param end Where to stop searching in `buf` (exclusive). **Default:** + * `buf.length`. + * @param encoding If `value` is a string, this is the encoding used to + * determine the binary representation of the string that will be searched for in + * `buf`. **Default:** `'utf8'`. + * @returns The index of the first occurrence of `value` in `buf`, or + * `-1` if `buf` does not contain `value`. + */ + indexOf( + value: string | number | Uint8Array, + start?: number, + end?: number, + encoding?: BufferEncoding, + ): number; + indexOf(value: string | number | Uint8Array, start: number, encoding: BufferEncoding): number; indexOf(value: string | number | Uint8Array, encoding: BufferEncoding): number; /** * Identical to `buf.indexOf()`, except the last occurrence of `value` is found @@ -1649,12 +1664,13 @@ declare module "node:buffer" { * // Prints: 4 * ``` * - * If `value` is not a string, number, or `Buffer`, this method will throw a `TypeError`. If `value` is a number, it will be coerced to a valid byte value, + * If `value` is not a string, number, or `Buffer`, this method will throw a + * `TypeError`. If `value` is a number, it will be coerced to a valid byte value, * an integer between 0 and 255. * * If `byteOffset` is not a number, it will be coerced to a number. Any arguments * that coerce to `NaN`, like `{}` or `undefined`, will search the whole buffer. - * This behavior matches [`String.prototype.lastIndexOf()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/lastIndexOf). + * This behavior matches `String.prototype.lastIndexOf()`. * * ```js * import { Buffer } from 'node:buffer'; @@ -1680,11 +1696,24 @@ declare module "node:buffer" { * If `value` is an empty string or empty `Buffer`, `byteOffset` will be returned. * @since v6.0.0 * @param value What to search for. - * @param [byteOffset=buf.length - 1] Where to begin searching in `buf`. If negative, then offset is calculated from the end of `buf`. - * @param [encoding='utf8'] If `value` is a string, this is the encoding used to determine the binary representation of the string that will be searched for in `buf`. - * @return The index of the last occurrence of `value` in `buf`, or `-1` if `buf` does not contain `value`. - */ - lastIndexOf(value: string | number | Uint8Array, byteOffset?: number, encoding?: BufferEncoding): number; + * @param start Where to begin searching in `buf`. If negative, then + * offset is calculated from the end of `buf`. **Default:** + * `buf.length - 1`. + * @param end Where to stop searching in `buf` (exclusive). **Default:** + * `buf.length`. + * @param encoding If `value` is a string, this is the encoding used to + * determine the binary representation of the string that will be searched for in + * `buf`. **Default:** `'utf8'`. + * @returns The index of the last occurrence of `value` in `buf`, or + * `-1` if `buf` does not contain `value`. + */ + lastIndexOf( + value: string | number | Uint8Array, + start?: number, + end?: number, + encoding?: BufferEncoding, + ): number; + lastIndexOf(value: string | number | Uint8Array, start: number, encoding: BufferEncoding): number; lastIndexOf(value: string | number | Uint8Array, encoding: BufferEncoding): number; /** * Equivalent to `buf.indexOf() !== -1`. @@ -1711,12 +1740,22 @@ declare module "node:buffer" { * ``` * @since v5.3.0 * @param value What to search for. - * @param [byteOffset=0] Where to begin searching in `buf`. If negative, then offset is calculated from the end of `buf`. - * @param [encoding='utf8'] If `value` is a string, this is its encoding. - * @return `true` if `value` was found in `buf`, `false` otherwise. - */ - includes(value: string | number | Buffer, byteOffset?: number, encoding?: BufferEncoding): boolean; - includes(value: string | number | Buffer, encoding: BufferEncoding): boolean; + * @param start Where to begin searching in `buf`. If negative, then + * offset is calculated from the end of `buf`. **Default:** `0`. + * @param end Where to stop searching in `buf` (exclusive). **Default:** + * `buf.length`. + * @param encoding If `value` is a string, this is its encoding. + * **Default:** `'utf8'`. + * @returns `true` if `value` was found in `buf`, `false` otherwise. + */ + includes( + value: string | number | Uint8Array, + start?: number, + end?: number, + encoding?: BufferEncoding, + ): boolean; + includes(value: string | number | Uint8Array, start: number, encoding: BufferEncoding): boolean; + includes(value: string | number | Uint8Array, encoding: BufferEncoding): boolean; } var Buffer: BufferConstructor; } diff --git a/types/node/crypto.d.ts b/types/node/crypto.d.ts index a0e54f922f476f..3d5aa3c5e582b4 100644 --- a/types/node/crypto.d.ts +++ b/types/node/crypto.d.ts @@ -1373,9 +1373,9 @@ declare module "node:crypto" { */ update(data: string | NodeJS.ArrayBufferView, inputEncoding?: BufferEncoding): Verify; /** - * Verifies the provided data using the given `object` and `signature`. + * Verifies the provided data using the given `key` and `signature`. * - * If `object` is not a `KeyObject`, this function behaves as if `object` had been passed to {@link createPublicKey}. If it is an + * If `key` is not a `KeyObject`, this function behaves as if `key` had been passed to {@link createPublicKey}. If it is an * object, the following additional properties can be passed: * * The `signature` argument is the previously calculated signature for the data, in @@ -1392,7 +1392,7 @@ declare module "node:crypto" { * @since v0.1.92 */ verify( - object: + key: | KeyLike | VerifyKeyObjectInput | VerifyPublicKeyInput @@ -1470,8 +1470,10 @@ declare module "node:crypto" { * If `encoding` is provided a string is returned; otherwise a `Buffer` is returned. * * This function is a thin wrapper around [`DH_generate_key()`](https://www.openssl.org/docs/man3.0/man3/DH_generate_key.html). In particular, - * once a private key has been generated or set, calling this function only updates - * the public key but does not generate a new private key. + * once a private key has been generated or set, calling this function only + * recomputes the public key from the existing private key. Since the public key is + * determined by the private key, the result will be the same unless the private key + * has been changed via `diffieHellman.setPrivateKey()`. * @since v0.5.0 * @param encoding The `encoding` of the return value. */ @@ -2997,6 +2999,7 @@ declare module "node:crypto" { */ disableEntropyCache?: boolean | undefined; } + interface RandomUUIDV7Options extends RandomUUIDOptions {} type UUID = `${string}-${string}-${string}-${string}-${string}`; /** * Generates a random [RFC 4122](https://www.rfc-editor.org/rfc/rfc4122.txt) version 4 UUID. The UUID is generated using a @@ -3004,6 +3007,16 @@ declare module "node:crypto" { * @since v15.6.0, v14.17.0 */ function randomUUID(options?: RandomUUIDOptions): UUID; + /** + * Generates a random [RFC 9562](https://www.rfc-editor.org/rfc/rfc9562.txt) version 7 UUID. The UUID contains a millisecond + * precision Unix timestamp in the most significant 48 bits, followed by + * cryptographically secure random bits for the remaining fields, making it + * suitable for use as a database key with time-based sorting. The embedded + * timestamp relies on a non-monotonic clock and is not guaranteed to be strictly + * increasing. + * @since v26.1.0 + */ + function randomUUIDv7(options?: RandomUUIDV7Options): UUID; interface X509CheckOptions { subject?: "always" | "default" | "never" | undefined; wildcards?: boolean | undefined; diff --git a/types/node/diagnostics_channel.d.ts b/types/node/diagnostics_channel.d.ts index a6deb7dcd6e17d..360e17ff2dbc5d 100644 --- a/types/node/diagnostics_channel.d.ts +++ b/types/node/diagnostics_channel.d.ts @@ -102,6 +102,36 @@ declare module "node:diagnostics_channel" { function tracingChannel( nameOrChannels: string | TracingChannelCollection, ): TracingChannel; + /** + * Creates a {@link BoundedChannel} wrapper for the given channels. If a name is + * given, the corresponding channels will be created in the form of + * `tracing:${name}:${eventType}` where `eventType` is `start` or `end`. + * + * A `BoundedChannel` is a simplified version of {@link TracingChannel} that only + * traces synchronous operations. It only has `start` and `end` events, without + * `asyncStart`, `asyncEnd`, or `error` events, making it suitable for tracing + * operations that don't involve asynchronous continuations or error handling. + * + * ```js + * import { boundedChannel, channel } from 'node:diagnostics_channel'; + * + * const wc = boundedChannel('my-operation'); + * + * // or... + * + * const wc2 = boundedChannel({ + * start: channel('tracing:my-operation:start'), + * end: channel('tracing:my-operation:end'), + * }); + * ``` + * @since v26.1.0 + * @experimental + * @param nameOrChannels Channel name or + * object containing all the [BoundedChannel Channels](https://nodejs.org/docs/latest-v26.x/api/diagnostics_channel.html#boundedchannel-channels) + */ + function boundedChannel( + nameOrChannels: string | BoundedChannelCollection, + ): BoundedChannel; /** * The class `Channel` represents an individual named channel within the data * pipeline. It is used to track subscribers and to publish messages when there @@ -112,6 +142,7 @@ declare module "node:diagnostics_channel" { * @since v15.1.0, v14.17.0 */ class Channel { + private constructor(); readonly name: string | symbol; /** * Check if there are active subscribers to this channel. This is helpful if @@ -132,7 +163,6 @@ declare module "node:diagnostics_channel" { * @since v15.1.0, v14.17.0 */ readonly hasSubscribers: boolean; - private constructor(name: string | symbol); /** * Publish a message to any subscribers to the channel. This will trigger * message handlers synchronously so they will execute within the same context. @@ -277,7 +307,48 @@ declare module "node:diagnostics_channel" { thisArg?: ThisArg, ...args: Args ): Result; + /** + * Creates a disposable scope that binds the given data to any AsyncLocalStorage + * instances bound to the channel and publishes it to subscribers. The scope + * automatically restores the previous storage contexts when disposed. + * + * This method enables the use of JavaScript's explicit resource management + * (`using` syntax with `Symbol.dispose`) to manage store contexts without + * closure wrapping. + * + * ```js + * import { channel } from 'node:diagnostics_channel'; + * import { AsyncLocalStorage } from 'node:async_hooks'; + * + * const store = new AsyncLocalStorage(); + * const ch = channel('my-channel'); + * + * ch.bindStore(store, (message) => { + * return { ...message, timestamp: Date.now() }; + * }); + * + * { + * using scope = ch.withStoreScope({ request: 'data' }); + * // Store is entered, data is published + * console.log(store.getStore()); // { request: 'data', timestamp: ... } + * } + * // Store is automatically restored on scope exit + * ``` + * @since v26.1.0 + * @experimental + */ + withStoreScope(data: ContextType): RunStoresScope; } + /** + * The class `RunStoresScope` represents a disposable scope created by + * `channel.withStoreScope(data)`. It manages the lifecycle of store + * contexts and ensures they are properly restored when the scope exits. + * + * The scope must be used with the `using` syntax to ensure proper disposal. + * @since v26.1.0 + * @experimental + */ + interface RunStoresScope extends Disposable {} interface TracingChannelSubscribers { start: (message: ContextType) => void; end: ( @@ -355,7 +426,7 @@ declare module "node:diagnostics_channel" { * @experimental * @param subscribers Set of `TracingChannel Channels` subscribers */ - subscribe(subscribers: TracingChannelSubscribers): void; + subscribe(subscribers: NodeJS.PartialOptions>): void; /** * Helper to unsubscribe a collection of functions from the corresponding channels. * This is the same as calling `channel.unsubscribe(onMessage)` on each channel @@ -389,7 +460,7 @@ declare module "node:diagnostics_channel" { * @param subscribers Set of `TracingChannel Channels` subscribers * @return `true` if all handlers were successfully unsubscribed, and `false` otherwise. */ - unsubscribe(subscribers: TracingChannelSubscribers): void; + unsubscribe(subscribers: NodeJS.PartialOptions>): void; /** * Trace a synchronous function call. This will always produce a `start event` and `end event` around the execution and may produce an `error event` if the given function throws an error. * This will run the given function using `channel.runStores(context, ...)` on the `start` channel which ensures all @@ -554,6 +625,169 @@ declare module "node:diagnostics_channel" { */ readonly hasSubscribers: boolean; } + interface BoundedChannelSubscribers { + start: (message: ContextType) => void; + end: (message: ContextType) => void; + } + interface BoundedChannelCollection { + start: Channel; + end: Channel; + } + /** + * The class `BoundedChannel` is a simplified version of {@link TracingChannel} that + * only traces synchronous operations. It consists of two channels (`start` and + * `end`) instead of five, omitting the `asyncStart`, `asyncEnd`, and `error` + * events. This makes it suitable for tracing operations that don't involve + * asynchronous continuations or error handling. + * + * Like `TracingChannel`, it is recommended to create and reuse a single + * `BoundedChannel` at the top-level of the file rather than creating them + * dynamically. + * @since v26.1.0 + * @experimental + */ + interface BoundedChannel + extends BoundedChannelCollection + { + /** + * Check if any of the `start` or `end` channels have subscribers. + * + * ```js + * import { boundedChannel } from 'node:diagnostics_channel'; + * + * const wc = boundedChannel('my-operation'); + * + * if (wc.hasSubscribers) { + * // There are subscribers, perform traced operation + * } + * ``` + * @since v26.1.0 + */ + readonly hasSubscribers: boolean; + /** + * Subscribe to the bounded channel events. This is equivalent to calling + * [`channel.subscribe(onMessage)`][] on each channel individually. + * + * ```mjs + * import { boundedChannel } from 'node:diagnostics_channel'; + * + * const wc = boundedChannel('my-operation'); + * + * wc.subscribe({ + * start(message) { + * // Handle start + * }, + * end(message) { + * // Handle end + * }, + * }); + * ``` + * @since v26.1.0 + * @param handlers Set of channel subscribers + */ + subscribe(handlers: NodeJS.PartialOptions>): void; + /** + * Unsubscribe from the bounded channel events. This is equivalent to calling + * [`channel.unsubscribe(onMessage)`][] on each channel individually. + * + * ```js + * import { boundedChannel } from 'node:diagnostics_channel'; + * + * const wc = boundedChannel('my-operation'); + * + * const handlers = { + * start(message) {}, + * end(message) {}, + * }; + * + * wc.subscribe(handlers); + * wc.unsubscribe(handlers); + * ``` + * @since v26.1.0 + * @param handlers Set of channel subscribers + * @returns `true` if all handlers were successfully unsubscribed, + * `false` otherwise. + */ + unsubscribe(handlers: NodeJS.PartialOptions>): boolean; + /** + * Trace a synchronous function call. This will produce a `start` event and `end` + * event around the execution. This runs the given function using + * [`channel.runStores(context, ...)`][] on the `start` channel which ensures all + * events have any bound stores set to match this trace context. + * + * ```js + * import { boundedChannel } from 'node:diagnostics_channel'; + * + * const wc = boundedChannel('my-operation'); + * + * const result = wc.run({ operationId: '123' }, () => { + * // Perform operation + * return 42; + * }); + * ``` + * @since v26.1.0 + * @param context Shared object to correlate events through + * @param fn Function to wrap a trace around + * @param thisArg The receiver to be used for the function call + * @param args Optional arguments to pass to the function + * @returns The return value of the given function + */ + run( + fn: (this: ThisArg, ...args: Args) => Result, + context?: ContextType, + thisArg?: ThisArg, + ...args: Args + ): Result; + /** + * Create a disposable scope for tracing a synchronous operation using JavaScript's + * explicit resource management (`using` syntax). The scope automatically publishes + * `start` and `end` events, enters bound stores, and handles cleanup when disposed. + * + * ```js + * import { boundedChannel } from 'node:diagnostics_channel'; + * + * const wc = boundedChannel('my-operation'); + * + * const context = { operationId: '123' }; + * { + * using scope = wc.withScope(context); + * // Stores are entered, start event is published + * + * // Perform work and set result on context + * context.result = 42; + * } + * // End event is published, stores are restored automatically + * ``` + * @since v26.1.0 + * @param context Shared object to correlate events through + * @returns Disposable scope object + */ + withScope(context: ContextType): BoundedChannelScope; + } + /** + * The class `BoundedChannelScope` represents a disposable scope created by + * `boundedChannel.withScope(context)`. It manages the lifecycle of a traced + * operation, automatically publishing events and managing store contexts. + * + * The scope must be used with the `using` syntax to ensure proper disposal. + * + * ```js + * import { boundedChannel } from 'node:diagnostics_channel'; + * + * const wc = boundedChannel('my-operation'); + * + * const context = {}; + * { + * using scope = wc.withScope(context); + * // Start event is published, stores are entered + * context.result = performOperation(); + * // End event is automatically published at end of block + * } + * ``` + * @since v26.1.0 + * @experimental + */ + interface BoundedChannelScope extends Disposable {} } declare module "diagnostics_channel" { export * from "node:diagnostics_channel"; diff --git a/types/node/dns.d.ts b/types/node/dns.d.ts index 7a1d41109965ae..ab5e841459715f 100644 --- a/types/node/dns.d.ts +++ b/types/node/dns.d.ts @@ -34,7 +34,7 @@ declare module "node:dns" { */ all?: boolean | undefined; /** - * When `verbatim`, the resolved addresses are return unsorted. When `ipv4first`, the resolved addresses are sorted + * When `verbatim`, the resolved addresses are returned unsorted. When `ipv4first`, the resolved addresses are sorted * by placing IPv4 addresses before IPv6 addresses. When `ipv6first`, the resolved addresses are sorted by placing IPv6 * addresses before IPv4 addresses. Default value is configurable using * {@link setDefaultResultOrder} or [`--dns-result-order`](https://nodejs.org/docs/latest-v26.x/api/cli.html#--dns-result-orderorder). diff --git a/types/node/ffi.d.ts b/types/node/ffi.d.ts new file mode 100644 index 00000000000000..ba5806f08c291a --- /dev/null +++ b/types/node/ffi.d.ts @@ -0,0 +1,486 @@ +declare module "node:ffi" { + import { NonSharedBuffer } from "node:buffer"; + interface FunctionSignature { + return?: ReturnType | undefined; + arguments?: readonly ArgumentType[] | undefined; + } + interface FunctionDefinitions { + [symbol: string]: FunctionSignature; + } + type CallbackFunction = ( + ...args: { [K in keyof P]: ArgumentTypeMap[DataTypeMap[P[K]]] } + ) => ReturnTypeMap[DataTypeMap[R]]; + interface WrappedFunction + extends CallbackFunction + { + readonly pointer: bigint; + } + type CallbackFunctionFromSignature = CallbackFunction< + ReturnTypeFromFunctionSignature, + ArgumentTypesFromFunctionSignature + >; + type WrappedFunctionFromSignature = WrappedFunction< + ReturnTypeFromFunctionSignature, + ArgumentTypesFromFunctionSignature + >; + type WrappedFunctionsFromDefinitions = { + [K in keyof T]: WrappedFunctionFromSignature; + }; + type ReturnTypeFromFunctionSignature = "return" extends keyof T + ? T extends { return: infer R extends ReturnType } ? R : any + : "void"; + type ArgumentTypesFromFunctionSignature = "arguments" extends keyof T + ? T extends { arguments: infer P extends readonly ArgumentType[] } ? P : any[] + : []; + interface DynamicLibraryResult extends Disposable { + lib: DynamicLibrary; + functions: WrappedFunctionsFromDefinitions; + } + /** + * The native shared library suffix for the current platform: + * + * * `'dylib'` on macOS + * * `'so'` on Unix-like platforms + * * `'dll'` on Windows + * + * This can be used to build portable library paths: + * + * ```js + * const { suffix } = require('node:ffi'); + * + * const path = `libsqlite3.${suffix}`; + * ``` + * @since v26.1.0 + */ + const suffix: string; + /** + * Loads a dynamic library and resolves the requested function definitions. + * + * On Windows passing `null` is not supported. + * + * When `definitions` is omitted, `functions` is returned as an empty object until + * symbols are resolved explicitly. + * + * The returned object also implements the explicit resource management protocol, + * so it can be used with the `using` declaration. Disposing the returned + * object closes the library handle. + * + * ```js + * import { dlopen } from 'node:ffi'; + * + * { + * using handle = dlopen('./mylib.so', { + * add_i32: { arguments: ['i32', 'i32'], return: 'i32' }, + * }); + * console.log(handle.functions.add_i32(20, 22)); + * } // handle.lib.close() is invoked automatically here. + * ``` + * + * ```js + * import { dlopen } from 'node:ffi'; + * + * const { lib, functions } = dlopen('./mylib.so', { + * add_i32: { arguments: ['i32', 'i32'], return: 'i32' }, + * string_length: { arguments: ['pointer'], return: 'u64' }, + * }); + * + * console.log(functions.add_i32(20, 22)); + * ``` + * @since v26.1.0 + * @param path Path to a dynamic library, or `null` to resolve symbols + * from the current process image. + * @param definitions Symbol definitions to resolve immediately. + */ + function dlopen( + path: string | null, + definitions?: T, + ): DynamicLibraryResult; + /** + * Closes a dynamic library. + * + * This is equivalent to calling `handle.close()`. + * @since v26.1.0 + */ + function dlclose(handle: DynamicLibrary): void; + /** + * Resolves a symbol address from a loaded library. + * + * This is equivalent to calling `handle.getSymbol(symbol)`. + * @since v26.1.0 + */ + function dlsym(handle: DynamicLibrary, symbol: string): bigint; + /** + * @since v26.1.0 + */ + class DynamicLibrary { + /** + * Loads the dynamic library without resolving any functions eagerly. + * + * On Windows passing `null` is not supported. + * + * ```js + * const { DynamicLibrary } = require('node:ffi'); + * + * const lib = new DynamicLibrary('./mylib.so'); + * ``` + * @param path Path to a dynamic library, or `null` to resolve symbols + * from the current process image. + */ + constructor(path: string | null); + /** + * The path used to load the library. + */ + readonly path: string; + /** + * An object containing previously resolved symbol addresses as `bigint` values. + */ + readonly symbols: { [symbol: string]: bigint }; + /** + * Closes the library handle. + * + * `DynamicLibrary` implements the explicit resource management protocol, so a + * library instance can be managed with the `using` declaration. Leaving the + * enclosing scope invokes `library.close()` automatically. + * + * ```js + * import { DynamicLibrary } from 'node:ffi'; + * + * { + * using lib = new DynamicLibrary('./mylib.so'); + * // Use `lib` here; `lib.close()` is called when the block exits. + * } + * ``` + * + * Calling `library.close()` (or disposing the library) more than once is a no-op. + * + * After a library has been closed: + * + * * Resolved function wrappers become invalid. + * * Further symbol and function resolution throws. + * * Registered callbacks are invalidated. + * + * Closing a library does not make previously exported callback pointers safe to + * reuse. Node.js does not track or revoke callback pointers that have already + * been handed to native code. + * + * If native code still holds a callback pointer after `library.close()` or after + * `library.unregisterCallback(pointer)`, invoking that pointer has undefined + * behavior, is not allowed, and is dangerous: it can crash the process, produce + * incorrect output, or corrupt memory. Native code must stop using callback + * addresses before the library is closed or before the callback is unregistered. + * + * Calling `library.close()` from one of the library's active callbacks is + * unsupported and dangerous. The callback must return before the library is + * closed. + */ + close(): void; + /** + * Calls `library.close()`. This allows `DynamicLibrary` instances to be used with + * the `using` declaration for automatic cleanup when the enclosing scope + * exits. It is a no-op on a library that has already been closed. + * @since v26.1.0 + */ + [Symbol.dispose](): void; + /** + * Resolves a symbol and returns a callable JavaScript wrapper. + * + * The returned function has a `.pointer` property containing the native function + * address as a `bigint`. + * + * If the same symbol has already been resolved, requesting it again with a + * different signature throws. + * + * ```js + * const { DynamicLibrary } = require('node:ffi'); + * + * const lib = new DynamicLibrary('./mylib.so'); + * const add = lib.getFunction('add_i32', { + * arguments: ['i32', 'i32'], + * return: 'i32', + * }); + * + * console.log(add(20, 22)); + * console.log(add.pointer); + * ``` + */ + getFunction(name: string, signature: T): WrappedFunctionFromSignature; + /** + * When `definitions` is provided, resolves each named symbol and returns an + * object containing callable wrappers. + * + * When `definitions` is omitted, returns wrappers for all functions that have + * already been resolved on the library. + */ + getFunctions(): { [symbol: string]: WrappedFunction }; + getFunctions(definitions: T): WrappedFunctionsFromDefinitions; + /** + * Resolves a symbol and returns its native address as a `bigint`. + */ + getSymbol(name: string): bigint; + /** + * Returns an object containing all previously resolved symbol addresses. + */ + getSymbols(): Record; + /** + * Creates a native callback pointer backed by a JavaScript function. + * + * When `signature` is omitted, the callback uses a default `void ()` signature. + * + * The return value is the callback pointer address as a `bigint`. It can be + * passed to native functions expecting a callback pointer. + * + * ```js + * const { DynamicLibrary } = require('node:ffi'); + * + * const lib = new DynamicLibrary('./mylib.so'); + * + * const callback = lib.registerCallback( + * { arguments: ['i32'], return: 'i32' }, + * (value) => value * 2, + * ); + * ``` + * + * Callbacks are subject to the following restrictions: + * + * * They must be invoked on the same system thread where they were created. + * * They must not throw exceptions. + * * They must not return promises. + * * They must return a value compatible with the declared return type. + * * They must not call `library.close()` on their owning library while running. + * * They must not unregister themselves while running. + * + * Closing the owning library or unregistering the currently executing callback + * from inside the callback is unsupported and dangerous. Doing so may crash the + * process, produce incorrect output, or corrupt memory. + */ + registerCallback(callback: () => void): bigint; + registerCallback( + signature: T, + callback: CallbackFunctionFromSignature, + ): bigint; + /** + * Releases a callback previously created with `library.registerCallback()`. + * + * Calling `library.unregisterCallback(pointer)` for a callback that is currently + * executing is unsupported and dangerous. The callback must return before it is + * unregistered. + * + * After `library.unregisterCallback(pointer)` returns, invoking that callback + * pointer from native code has undefined behavior, is not allowed, and is + * dangerous: it can crash the process, produce incorrect output, or corrupt + * memory. + */ + unregisterCallback(pointer: bigint): void; + /** + * Keeps the callback strongly referenced by JavaScript. + */ + refCallback(pointer: bigint): void; + /** + * Allows the callback to become weakly referenced by JavaScript. + * + * If the callback function is later garbage collected, subsequent native + * invocations become a no-op. Non-void return values are zero-initialized before + * returning to native code. + */ + unrefCallback(pointer: bigint): void; + } + function getInt8(pointer: bigint, offset?: number): number; + function getUint8(pointer: bigint, offset?: number): number; + function getInt16(pointer: bigint, offset?: number): number; + function getUint16(pointer: bigint, offset?: number): number; + function getInt32(pointer: bigint, offset?: number): number; + function getUint32(pointer: bigint, offset?: number): number; + function getInt64(pointer: bigint, offset?: number): bigint; + function getUint64(pointer: bigint, offset?: number): bigint; + function getFloat32(pointer: bigint, offset?: number): number; + function getFloat64(pointer: bigint, offset?: number): number; + function setInt8(pointer: bigint, offset: number, value: number): void; + function setUint8(pointer: bigint, offset: number, value: number): void; + function setInt16(pointer: bigint, offset: number, value: number): void; + function setUint16(pointer: bigint, offset: number, value: number): void; + function setInt32(pointer: bigint, offset: number, value: number): void; + function setUint32(pointer: bigint, offset: number, value: number): void; + function setInt64(pointer: bigint, offset: number, value: number | bigint): void; + function setUint64(pointer: bigint, offset: number, value: number | bigint): void; + function setFloat32(pointer: bigint, offset: number, value: number): void; + function setFloat64(pointer: bigint, offset: number, value: number): void; + /** + * Reads a NUL-terminated UTF-8 string from native memory. + * + * If `pointer` is `0n`, `null` is returned. + * + * This function does not validate that `pointer` refers to readable memory or + * that the pointed-to data is terminated with `\0`. Passing an invalid pointer, + * a pointer to freed memory, or a pointer to bytes without a terminating NUL can + * read unrelated memory, crash the process, or produce truncated or garbled + * output. + * @since v26.1.0 + */ + function toString(pointer: bigint): string | null; + /** + * Creates a `Buffer` from native memory. + * + * When `copy` is `true`, the returned `Buffer` owns its own copied memory. + * When `copy` is `false`, the returned `Buffer` references the original native + * memory directly. + * + * Using `copy: false` is a zero-copy escape hatch. The returned `Buffer` is a + * writable view onto foreign memory, so writes in JavaScript update the original + * native memory directly. The caller must guarantee that: + * + * * `pointer` remains valid for the entire lifetime of the returned `Buffer`. + * * `length` stays within the allocated native region. + * * no native code frees or repurposes that memory while JavaScript still uses + * the `Buffer`. + * * Memory protection is observed. For example, read-only memory pages must not + * be written to. + * + * If these guarantees are not met, reading or writing the `Buffer` can corrupt + * memory or crash the process. + * @since v26.1.0 + * @param copy When `false`, creates a zero-copy view. **Default:** `true`. + */ + function toBuffer(pointer: bigint, length: number, copy?: boolean): NonSharedBuffer; + /** + * Creates an `ArrayBuffer` from native memory. + * + * When `copy` is `true`, the returned `ArrayBuffer` contains copied bytes. + * When `copy` is `false`, the returned `ArrayBuffer` references the original + * native memory directly. + * + * The same lifetime and bounds requirements described for + * `ffi.toBuffer(pointer, length, copy)` apply + * here. With `copy: false`, the + * returned `ArrayBuffer` is a zero-copy view of foreign memory and is only safe + * while that memory remains allocated, unchanged in layout, and valid for the + * entire exposed range. + * @since v26.1.0 + * @param copy When `false`, creates a zero-copy view. **Default:** `true`. + */ + function toArrayBuffer(pointer: bigint, length: number, copy?: boolean): ArrayBuffer; + /** + * Copies a JavaScript string into native memory and appends a trailing NUL + * terminator. + * + * `length` must be large enough to hold the full encoded string plus the trailing + * NUL terminator. For UTF-16 and UCS-2 encodings, the trailing terminator uses + * two zero bytes. + * + * `pointer` must refer to writable native memory with at least `length` bytes of + * available storage. This function does not allocate memory on its own. + * + * `string` must be a JavaScript string. `encoding` must be a string. + * @since v26.1.0 + * @param encoding **Default:** `'utf8'`. + */ + function exportString(string: string, pointer: bigint, length: number, encoding?: BufferEncoding): void; + /** + * Copies bytes from a `Buffer` into native memory. + * + * `length` must be at least `buffer.length`. + * + * `pointer` must refer to writable native memory with at least `length` bytes of + * available storage. This function does not allocate memory on its own. + * + * `buffer` must be a Node.js `Buffer`. + * @since v26.1.0 + */ + function exportBuffer(buffer: Buffer, pointer: bigint, length: number): void; + /** + * Copies bytes from an `ArrayBuffer` into native memory. + * + * `length` must be at least `arrayBuffer.byteLength`. + * + * `pointer` must refer to writable native memory with at least `length` bytes of + * available storage. This function does not allocate memory on its own. + * @since v26.1.0 + */ + function exportArrayBuffer(arrayBuffer: ArrayBuffer, pointer: bigint, length: number): void; + /** + * Copies bytes from an `ArrayBufferView` into native memory. + * + * `length` must be at least `arrayBufferView.byteLength`. + * + * `pointer` must refer to writable native memory with at least `length` bytes of + * available storage. This function does not allocate memory on its own. + * @since v26.1.0 + */ + function exportArrayBufferView(arrayBufferView: NodeJS.ArrayBufferView, pointer: bigint, length: number): void; + /** + * Returns the raw memory address of JavaScript-managed byte storage. + * + * This is unsafe and dangerous. The returned pointer can become invalid if the + * underlying memory is detached, resized, transferred, or otherwise invalidated. + * Using stale pointers can cause memory corruption or process crashes. + * @since v26.1.0 + */ + function getRawPointer(source: ArrayBuffer | NodeJS.ArrayBufferView): bigint; + type ReturnType = { [K in keyof DataTypeMap]: K }[keyof DataTypeMap]; + type ArgumentType = Exclude; + interface DataTypeMap { + void: "void"; + char: "number"; + bool: "number"; + i8: "number"; + int8: "number"; + u8: "number"; + uint8: "number"; + i16: "number"; + int16: "number"; + u16: "number"; + uint16: "number"; + i32: "number"; + int32: "number"; + u32: "number"; + uint32: "number"; + i64: "bigint"; + int64: "bigint"; + u64: "bigint"; + uint64: "bigint"; + float: "number"; + f32: "number"; + double: "number"; + f64: "number"; + pointer: "pointer"; + ptr: "pointer"; + function: "pointer"; + buffer: "pointer"; + arraybuffer: "pointer"; + string: "pointer"; + str: "pointer"; + } + interface ArgumentTypeMap { + "number": number; + "bigint": bigint; + "pointer": bigint | string | ArrayBuffer | NodeJS.ArrayBufferView | null; + } + interface ReturnTypeMap { + // eslint-disable-next-line @typescript-eslint/no-invalid-void-type + "void": void; + "number": number; + "bigint": bigint; + "pointer": bigint | null; + } + enum types { + VOID = "void", + POINTER = "pointer", + BUFFER = "buffer", + ARRAY_BUFFER = "arraybuffer", + FUNCTION = "function", + BOOL = "bool", + CHAR = "char", + STRING = "string", + FLOAT = "float", + DOUBLE = "double", + INT_8 = "int8", + UINT_8 = "uint8", + INT_16 = "int16", + UINT_16 = "uint16", + INT_32 = "int32", + UINT_32 = "uint32", + INT_64 = "int64", + UINT_64 = "uint64", + FLOAT_32 = "float32", + FLOAT_64 = "float64", + } +} diff --git a/types/node/fs.d.ts b/types/node/fs.d.ts index ed3219149762f1..9317f23166ffcf 100644 --- a/types/node/fs.d.ts +++ b/types/node/fs.d.ts @@ -126,6 +126,8 @@ declare module "node:fs" { bavail: T; /** Total file nodes in file system. */ files: T; + /** Fundamental file system block size. */ + frsize: T; /** Free file nodes in file system. */ ffree: T; } @@ -4576,6 +4578,7 @@ declare module "node:fs" { bigint: true; } interface StatOptions { + // TODO: add signal option once we sort its behavior out upstream bigint?: boolean | undefined; throwIfNoEntry?: boolean | undefined; } @@ -4675,12 +4678,6 @@ declare module "node:fs" { * @default process.cwd() */ cwd?: string | URL | undefined; - /** - * `true` if the glob should return paths as `Dirent`s, `false` otherwise. - * @default false - * @since v22.2.0 - */ - withFileTypes?: boolean | undefined; /** * Function to filter out files/directories or a * list of glob patterns to be excluded. If a function is provided, return @@ -4691,6 +4688,18 @@ declare module "node:fs" { * @default undefined */ exclude?: ((fileName: T) => boolean) | readonly string[] | undefined; + /** + * When `true`, symbolic links to directories are + * followed while expanding `**` patterns. + * @default false + */ + followSymlinks?: boolean | undefined; + /** + * `true` if the glob should return paths as `Dirent`s, `false` otherwise. + * @default false + * @since v22.2.0 + */ + withFileTypes?: boolean | undefined; } interface GlobOptionsWithFileTypes extends GlobOptions { withFileTypes: true; @@ -4702,6 +4711,9 @@ declare module "node:fs" { /** * Retrieves the files matching the specified pattern. * + * When `followSymlinks` is enabled, detected symbolic link cycles are not + * traversed recursively. + * * ```js * import { glob } from 'node:fs'; * @@ -4741,6 +4753,9 @@ declare module "node:fs" { ) => void, ): void; /** + * When `followSymlinks` is enabled, detected symbolic link cycles are not + * traversed recursively. + * * ```js * import { globSync } from 'node:fs'; * diff --git a/types/node/fs/promises.d.ts b/types/node/fs/promises.d.ts index e17dfdb3ae9288..a1c65992c671a4 100644 --- a/types/node/fs/promises.d.ts +++ b/types/node/fs/promises.d.ts @@ -1439,6 +1439,9 @@ declare module "node:fs/promises" { */ function cp(source: string | URL, destination: string | URL, opts?: CopyOptions): Promise; /** + * When `followSymlinks` is enabled, detected symbolic link cycles are not + * traversed recursively. + * * ```js * import { glob } from 'node:fs/promises'; * diff --git a/types/node/http.d.ts b/types/node/http.d.ts index 71523152e2b13b..d7bc18b028d2cf 100644 --- a/types/node/http.d.ts +++ b/types/node/http.d.ts @@ -1325,6 +1325,31 @@ declare module "node:http" { * @since v0.5.9 */ setTimeout(msecs: number, callback?: () => void): this; + /** + * An `AbortSignal` that is aborted when the underlying socket closes or the + * request is destroyed. The signal is created lazily on first access — no + * `AbortController` is allocated for requests that never use this property. + * + * This is useful for cancelling downstream asynchronous work such as database + * queries or `fetch` calls when a client disconnects mid-request. + * + * ```js + * import http from 'node:http'; + * + * http.createServer(async (req, res) => { + * try { + * const data = await fetch('https://example.com/api', { signal: req.signal }); + * res.end(JSON.stringify(await data.json())); + * } catch (err) { + * if (err.name === 'AbortError') return; + * res.statusCode = 500; + * res.end('Internal Server Error'); + * } + * }).listen(3000); + * ``` + * @since v26.1.0 + */ + readonly signal: AbortSignal; /** * **Only valid for request obtained from {@link Server}.** * diff --git a/types/node/index.d.ts b/types/node/index.d.ts index 3986214a90a2c6..5b8ec4d17d841f 100644 --- a/types/node/index.d.ts +++ b/types/node/index.d.ts @@ -66,6 +66,7 @@ /// /// /// +/// /// /// /// diff --git a/types/node/node-tests.ts b/types/node/node-tests.ts index 2031eb8a76f6a2..a05acfbf5999c4 100644 --- a/types/node/node-tests.ts +++ b/types/node/node-tests.ts @@ -11,6 +11,7 @@ import "./node-tests/diagnostics_channel"; import "./node-tests/dns"; import "./node-tests/events"; import "./node-tests/events-maps"; +import "./node-tests/ffi"; import "./node-tests/fs"; import "./node-tests/globals"; import "./node-tests/http"; diff --git a/types/node/node-tests/buffer.ts b/types/node/node-tests/buffer.ts index 934aac7d155ab6..ac3119cc20580c 100644 --- a/types/node/node-tests/buffer.ts +++ b/types/node/node-tests/buffer.ts @@ -249,6 +249,8 @@ result = b.write("asd", 123, 123, "hex"); index = buffer.indexOf("23", "hex"); index = buffer.indexOf("23", 1); index = buffer.indexOf("23", 1, "utf8"); + index = buffer.indexOf("23", 1, 3); + index = buffer.indexOf("23", 1, 3, "utf8"); index = buffer.indexOf(23); index = buffer.indexOf(buffer); } @@ -260,6 +262,8 @@ result = b.write("asd", 123, 123, "hex"); index = buffer.lastIndexOf("23", "hex"); index = buffer.lastIndexOf("23", 1); index = buffer.lastIndexOf("23", 1, "utf8"); + index = buffer.lastIndexOf("23", 1, 3); + index = buffer.lastIndexOf("23", 1, 3, "utf8"); index = buffer.lastIndexOf(23); index = buffer.lastIndexOf(buffer); } @@ -282,6 +286,8 @@ result = b.write("asd", 123, 123, "hex"); includes = buffer.includes("23", "hex"); includes = buffer.includes("23", 1); includes = buffer.includes("23", 1, "utf8"); + includes = buffer.includes("23", 1, 3); + includes = buffer.includes("23", 1, 3, "utf8"); includes = buffer.includes(23); includes = buffer.includes(23, 1); includes = buffer.includes(23, 1, "utf8"); diff --git a/types/node/node-tests/crypto.ts b/types/node/node-tests/crypto.ts index 1d41674c320804..af883c1af8f2b3 100644 --- a/types/node/node-tests/crypto.ts +++ b/types/node/node-tests/crypto.ts @@ -1551,6 +1551,13 @@ import { promisify } from "node:util"; crypto.randomUUID(); } +{ + crypto.randomUUIDv7({}); + crypto.randomUUIDv7({ disableEntropyCache: true }); + crypto.randomUUIDv7({ disableEntropyCache: false }); + crypto.randomUUIDv7(); +} + { const cert = new crypto.X509Certificate("dummy"); cert.ca; // $ExpectType boolean diff --git a/types/node/node-tests/diagnostics_channel.ts b/types/node/node-tests/diagnostics_channel.ts index 7ec4d7600bef12..8a0c91cf0c6d71 100644 --- a/types/node/node-tests/diagnostics_channel.ts +++ b/types/node/node-tests/diagnostics_channel.ts @@ -1,5 +1,13 @@ import { AsyncLocalStorage } from "node:async_hooks"; -import { Channel, channel, hasSubscribers, subscribe, tracingChannel, unsubscribe } from "node:diagnostics_channel"; +import { + boundedChannel, + Channel, + channel, + hasSubscribers, + subscribe, + tracingChannel, + unsubscribe, +} from "node:diagnostics_channel"; const ch1: Channel = channel(Symbol.for("test")); function listener(data: unknown) {} @@ -145,3 +153,19 @@ const hasSubs = hasSubscribers("test"); // @ts-expect-error - Only getter is implemented for `hasSubscribers` channels.hasSubscribers = false; } + +{ + const bc = boundedChannel<{ requestId: number }, number>("my-operation"); + bc.hasSubscribers; // $ExpectType boolean + + bc.subscribe({ + start(message) { + message.requestId; // $ExpectType number + }, + end(message) { + message.requestId; // $ExpectType number + }, + }); + + using scope = bc.withScope({ requestId: 123 }); +} diff --git a/types/node/node-tests/ffi.ts b/types/node/node-tests/ffi.ts new file mode 100644 index 00000000000000..14f42247b4b769 --- /dev/null +++ b/types/node/node-tests/ffi.ts @@ -0,0 +1,56 @@ +import { dlopen, DynamicLibrary, getInt32, setInt32, toString, types } from "node:ffi"; + +{ + using handle = dlopen("./mylib.so", { + add_i32: { arguments: ["i32", "i32"], return: "i32" }, + }); + // $ExpectType number + handle.functions.add_i32(20, 22); + // @ts-expect-error function type should be computed as (number, number) => number + handle.functions.add_i32(20n, 22n); +} + +{ + const { lib, functions } = dlopen("./mylib.so", { + add_i32: { arguments: ["i32", "i32"], return: "i32" }, + string_length: { arguments: ["pointer"], return: "u64" }, + }); + + const add_i32 = functions.add_i32; + // $ExpectType number + add_i32(20, 22); + + const string_length = functions.string_length; + // $ExpectType bigint + string_length("abc"); + + lib.close(); +} + +{ + using lib = new DynamicLibrary("./mylib.so"); + + const add = lib.getFunction("add_i32", { + arguments: [types.INT_32, types.INT_32], + return: types.INT_32, + }); + // $ExpectType number + add(20, 22); + // $ExpectType bigint + add.pointer; + + let callback: bigint; + callback = lib.registerCallback( + { arguments: ["i32"], return: "i32" }, + (value) => value * 2, + ); + callback = lib.registerCallback(() => {}); +} + +{ + const ptr = 0n; + setInt32(ptr, 0, 42); + getInt32(ptr, 0); // $ExpectType number + + toString(ptr); // $ExpectType string | null +} diff --git a/types/node/node-tests/fs.ts b/types/node/node-tests/fs.ts index 6ba2a6e850ab9e..10f0764a9a8022 100644 --- a/types/node/node-tests/fs.ts +++ b/types/node/node-tests/fs.ts @@ -1056,7 +1056,7 @@ const anyStatFs: fs.StatsFs | fs.BigIntStatsFs = fs.statfsSync(".", { bigint: Ma glob("**/*.js", (err, matches) => { matches; // $ExpectType string[] }); - glob("**/*.js", { cwd: new URL("") }, (err, matches) => { + glob("**/*.js", { cwd: new URL(""), followSymlinks: true }, (err, matches) => { matches; // $ExpectType string[] }); glob("**/*.js", { withFileTypes: true }, (err, matches) => { @@ -1109,7 +1109,7 @@ const anyStatFs: fs.StatsFs | fs.BigIntStatsFs = fs.statfsSync(".", { bigint: Ma }); globSync("**/*.js"); // $ExpectType string[] - globSync("**/*.js", { cwd: "/" }); // $ExpectType string[] + globSync("**/*.js", { cwd: "/", followSymlinks: true }); // $ExpectType string[] globSync("**/*.js", { withFileTypes: true }); // $ExpectType Dirent[] globSync("**/*.js", { withFileTypes: Math.random() > 0.5 }); // $ExpectType string[] | Dirent[] diff --git a/types/node/node-tests/http.ts b/types/node/node-tests/http.ts index a89053bd63b6d2..2db2bfdca9b81c 100644 --- a/types/node/node-tests/http.ts +++ b/types/node/node-tests/http.ts @@ -225,6 +225,8 @@ import * as url from "node:url"; incoming.pause(); incoming.resume(); + incoming.signal; // $ExpectType AbortSignal + // response const res: http.ServerResponse = new http.ServerResponse(incoming); diff --git a/types/node/node-tests/sqlite.ts b/types/node/node-tests/sqlite.ts index 6607d5876c6065..397508cb58dcdd 100644 --- a/types/node/node-tests/sqlite.ts +++ b/types/node/node-tests/sqlite.ts @@ -42,6 +42,9 @@ import { TextEncoder } from "node:util"; }, ); + database.deserialize(database.serialize()); + database.deserialize(database.serialize("db"), { dbName: "db" }); + const insert = database.prepare("INSERT INTO types (key, int, double, text, buf) VALUES (?, ?, ?, ?, ?)"); insert.setReadBigInts(true); insert.setAllowBareNamedParameters(true); diff --git a/types/node/node-tests/stream-iter.ts b/types/node/node-tests/stream-iter.ts index 45cfb162b6614e..8b4c9ecd406684 100644 --- a/types/node/node-tests/stream-iter.ts +++ b/types/node/node-tests/stream-iter.ts @@ -1,5 +1,23 @@ +import { createWriteStream } from "node:fs"; import { FileHandle, open } from "node:fs/promises"; -import { bytes, from, fromSync, pipeTo, pull, pullSync, text, textSync } from "node:stream/iter"; +import { Readable, Writable } from "node:stream"; +import { + AsyncStreamable, + bytes, + from, + fromReadable, + fromSync, + fromWritable, + pipeTo, + pull, + pullSync, + push, + text, + textSync, + toReadable, + toReadableSync, + toWritable, +} from "node:stream/iter"; import { setTimeout } from "node:timers/promises"; import { compressGzip, compressGzipSync, decompressGzip, decompressGzipSync } from "node:zlib/iter"; @@ -39,3 +57,49 @@ void async function() { return chunk; }); }; + +void async function() { + const readable = new Readable({ + read() { + this.push("hello world"); + this.push(null); + }, + }); + + const result: string = await text(fromReadable(readable)); + + const writable = new Writable({ + write(chunk, encoding, cb) { + console.log(chunk.toString()); + cb(); + }, + }); + + await pipeTo(from("hello world"), fromWritable(writable, { backpressure: "block" })); +}; + +{ + const source = pull(from("hello world"), compressGzip()); + const readable = toReadable(source); + + readable satisfies AsyncStreamable; + + readable.pipe(createWriteStream("output.gz")); +} + +{ + const source = fromSync("hello world"); + const readable = toReadableSync(source); + + readable.pipe(createWriteStream("output.txt")); +} + +void async function() { + const { writer, readable } = push(); + const writable = toWritable(writer); + + writable.write("hello"); + writable.end(); + + const result: string = await text(readable); +}; diff --git a/types/node/node-tests/test.ts b/types/node/node-tests/test.ts index 8f3a5b3abfa3f1..cfa09830fd656b 100644 --- a/types/node/node-tests/test.ts +++ b/types/node/node-tests/test.ts @@ -7,6 +7,7 @@ import { beforeEach, describe, expectFailure, + getTestContext, it, Mock, mock, @@ -68,6 +69,8 @@ run({ lineCoverage: 70, branchCoverage: 50, functionCoverage: 80, + randomize: true, + randomSeed: 1029384756, rerunFailuresFilePath: "/path/to/file.json", env: { MY_TEST_PATH: "/path/to/tests", @@ -518,6 +521,12 @@ suite("foo", (context) => { context.name; // $ExpectType AbortSignal context.signal; + // $ExpectType boolean + context.passed; + // $ExpectType number + context.attempt; + + context.diagnostic("diagnostic"); }); // Hooks @@ -1128,6 +1137,8 @@ test("planning with streams", (t: TestContext, done) => { }); }); +getTestContext(); // $ExpectType TestContext | SuiteContext | undefined + // Test custom assertion functions. { test.assert.register("isOdd", (n: number) => { diff --git a/types/node/node-tests/util.ts b/types/node/node-tests/util.ts index d42607a22134c6..d51fe300a47d0e 100644 --- a/types/node/node-tests/util.ts +++ b/types/node/node-tests/util.ts @@ -103,6 +103,10 @@ console.log( console.log( util.styleText("yellow", "text", { stream: process.stdout }), ); +// 6-digit hex color +console.log(util.styleText("#ff5733", "Orange text")); +// 3-digit hex color (shorthand) +console.log(util.styleText("#f00", "Red text")); // util.callbackify class callbackifyTest { diff --git a/types/node/node-tests/v8.ts b/types/node/node-tests/v8.ts index 2431c22c12007d..775efe2d50a589 100644 --- a/types/node/node-tests/v8.ts +++ b/types/node/node-tests/v8.ts @@ -95,4 +95,20 @@ v8.isStringOneByteRepresentation("你好"); // $ExpectType boolean { using profile: v8.SyncCPUProfileHandle = v8.startCpuProfile(); profile.stop(); // $ExpectType string + + v8.startCpuProfile({ + sampleInterval: 1048576, + maxBufferSize: 1073741823, + }); +} + +{ + using profile = v8.startHeapProfile(); + profile.stop(); // $ExpectType string + + v8.startHeapProfile({ + sampleInterval: 1048576, + stackDepth: 32, + forceGC: true, + }); } diff --git a/types/node/node-tests/worker_threads.ts b/types/node/node-tests/worker_threads.ts index eb835cc7b1e854..eb34d39dd7d86c 100644 --- a/types/node/node-tests/worker_threads.ts +++ b/types/node/node-tests/worker_threads.ts @@ -82,6 +82,13 @@ import { createContext } from "node:vm"; w.startHeapProfile().then(handle => { handle.stop().then(JSON.parse); }); + w.startHeapProfile({ + sampleInterval: 1048576, + stackDepth: 32, + forceGC: true, + }).then(handle => { + handle.stop().then(JSON.parse); + }); w.terminate().then(() => { // woot }); diff --git a/types/node/package.json b/types/node/package.json index 90b78c0b3c4a90..f866ca51599980 100644 --- a/types/node/package.json +++ b/types/node/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@types/node", - "version": "26.0.9999", + "version": "26.1.9999", "nonNpm": "conflict", "nonNpmDescription": "Node.js", "projects": [ diff --git a/types/node/process.d.ts b/types/node/process.d.ts index dd41214be293bb..197a7070ec0900 100644 --- a/types/node/process.d.ts +++ b/types/node/process.d.ts @@ -34,6 +34,7 @@ declare module "node:process" { "node:domain": typeof import("node:domain"); "events": typeof import("events"); "node:events": typeof import("node:events"); + "node:ffi": typeof import("node:ffi"); "fs": typeof import("fs"); "node:fs": typeof import("node:fs"); "fs/promises": typeof import("fs/promises"); @@ -2130,7 +2131,19 @@ declare module "node:process" { * All other resources are discarded by the system when the processes are swapped, without triggering * any exit or close events and without running any cleanup handler. * - * This function will never return, unless an error occurred. + * On success, all other resources are discarded by the system when the + * processes are swapped, without triggering any exit or close events, without + * running any JavaScript cleanup handler (for example `process.on('exit')`), + * and without invoking native `AtExit` callbacks registered through the + * embedder API. Callers that need to run cleanup logic should do so before + * calling `process.execve()`. + * + * This function does not return on success. If the underlying `execve(2)` + * system call fails, an `Error` is thrown whose `code` property is set to the + * corresponding `errno` string (for example, `'ENOENT'` when `file` does not + * exist), with `syscall` set to `'execve'` and `path` set to `file`. When + * `execve(2)` fails the current process continues to run with its state + * unchanged, so a caller may handle the error and take another action. * * This function is not available on Windows or IBM i. * @since v22.15.0 diff --git a/types/node/quic.d.ts b/types/node/quic.d.ts index 71437088b9b4df..a93b9b93aaea24 100644 --- a/types/node/quic.d.ts +++ b/types/node/quic.d.ts @@ -123,6 +123,13 @@ declare module "node:quic" { */ maxDatagramFrameSize?: bigint | number | undefined; } + interface SNIEntry { + keys: KeyObject | readonly KeyObject[]; + certs: ArrayBuffer | NodeJS.ArrayBufferView | ReadonlyArray; + ca?: ArrayBuffer | NodeJS.ArrayBufferView | ReadonlyArray | undefined; + crl?: ArrayBuffer | NodeJS.ArrayBufferView | ReadonlyArray | undefined; + verifyPrivateKey?: boolean | undefined; + } /** * @since v23.8.0 */ @@ -133,12 +140,25 @@ declare module "node:quic" { */ endpoint?: EndpointOptions | QuicEndpoint | undefined; /** - * The ALPN protocol identifier. - * @since v23.8.0 + * The ALPN (Application-Layer Protocol Negotiation) identifier(s). + * + * For **client** sessions, this is a single string specifying the protocol + * the client wants to use (e.g. `'h3'`). + * + * For **server** sessions, this is an array of protocol names in preference + * order that the server supports (e.g. `['h3', 'h3-29']`). During the TLS + * handshake, the server selects the first protocol from its list that the + * client also supports. + * + * The negotiated ALPN determines which Application implementation is used + * for the session. `'h3'` and `'h3-*'` variants select the HTTP/3 + * application; all other values select the default application. + * @since v26.1.0 */ - alpn?: string | undefined; + alpn?: string | readonly string[] | undefined; /** - * The CA certificates to use for sessions. + * The CA certificates to use for client sessions. For server sessions, CA + * certificates are specified per-identity in the `sessionOptions.sni` map. * @since v23.8.0 */ ca?: ArrayBuffer | NodeJS.ArrayBufferView | ReadonlyArray | undefined; @@ -151,7 +171,8 @@ declare module "node:quic" { */ cc?: `${constants.cc}` | undefined; /** - * The TLS certificates to use for sessions. + * The TLS certificates to use for client sessions. For server sessions, + * certificates are specified per-identity in the `sessionOptions.sni` map. * @since v23.8.0 */ certs?: ArrayBuffer | NodeJS.ArrayBufferView | ReadonlyArray | undefined; @@ -161,7 +182,8 @@ declare module "node:quic" { */ ciphers?: string | undefined; /** - * The CRL to use for sessions. + * The CRL to use for client sessions. For server sessions, CRLs are specified + * per-identity in the `sessionOptions.sni` map. * @since v23.8.0 */ crl?: ArrayBuffer | NodeJS.ArrayBufferView | ReadonlyArray | undefined; @@ -176,7 +198,8 @@ declare module "node:quic" { */ keylog?: boolean | undefined; /** - * The TLS crypto keys to use for sessions. + * The TLS crypto keys to use for client sessions. For server sessions, + * keys are specified per-identity in the `sessionOptions.sni` map. * @since v23.8.0 */ keys?: KeyObject | readonly KeyObject[] | undefined; @@ -224,10 +247,37 @@ declare module "node:quic" { */ handshakeTimeout?: bigint | number | undefined; /** - * The peer server name to target. - * @since v23.8.0 + * The peer server name to target (SNI). Defaults to `'localhost'`. + * @since v26.1.0 */ - sni?: string | undefined; + servername?: string | undefined; + /** + * An object mapping host names to TLS identity options for Server Name + * Indication (SNI) support. This is required for server sessions. The + * special key `'*'` specifies the default/fallback identity used when + * no other host name matches. Each entry may contain: + * + * ```js + * const endpoint = await listen(callback, { + * sni: { + * '*': { keys: [defaultKey], certs: [defaultCert] }, + * 'api.example.com': { keys: [apiKey], certs: [apiCert] }, + * 'www.example.com': { keys: [wwwKey], certs: [wwwCert], ca: [customCA] }, + * }, + * }); + * ``` + * + * Shared TLS options (such as `ciphers`, `groups`, `keylog`, and `verifyClient`) + * are specified at the top level of the session options and apply to all + * identities. Each SNI entry overrides only the per-identity certificate + * fields. + * + * The SNI map can be replaced at runtime using `endpoint.setSNIContexts()`, + * which atomically swaps the map for new sessions while existing sessions + * continue to use their original identity. + * @since v26.1.0 + */ + sni?: Record | undefined; /** * True to enable TLS tracing output. * @since v23.8.0 @@ -249,7 +299,9 @@ declare module "node:quic" { */ verifyClient?: boolean | undefined; /** - * True to require private key verification. + * True to require private key verification for client sessions. For server + * sessions, this option is specified per-identity in the + * `sessionOptions.sni` map. * @since v23.8.0 */ verifyPrivateKey?: boolean | undefined; @@ -406,6 +458,9 @@ declare module "node:quic" { */ validateAddress?: boolean | undefined; } + interface SetSNIContextsOptions { + replace?: boolean | undefined; + } /** * A `QuicEndpoint` encapsulates the local UDP-port binding for QUIC. It can be * used as both a client and a server. @@ -468,6 +523,32 @@ declare module "node:quic" { * @since v23.8.0 */ readonly destroyed: boolean; + /** + * True if the endpoint is actively listening for incoming connections. Read only. + * @since v26.1.0 + */ + readonly listening: boolean; + /** + * Replaces or updates the SNI TLS contexts for this endpoint. This allows + * changing the TLS identity (key/certificate) used for specific host names + * without restarting the endpoint. Existing sessions are unaffected — only + * new sessions will use the updated contexts. + * + * ```js + * endpoint.setSNIContexts({ + * 'api.example.com': { keys: [newApiKey], certs: [newApiCert] }, + * }); + * + * // Replace the entire SNI map + * endpoint.setSNIContexts({ + * 'api.example.com': { keys: [newApiKey], certs: [newApiCert] }, + * }, { replace: true }); + * ``` + * @since v26.1.0 + * @param entries An object mapping host names to TLS identity options. + * Each entry must include `keys` and `certs`. + */ + setSNIContexts(entries: Record, options?: SetSNIContextsOptions): void; /** * The statistics collected for an active session. Read only. * @since v23.8.0 diff --git a/types/node/sqlite.d.ts b/types/node/sqlite.d.ts index 8e1e8bac750b87..14ce8e1dbe2edc 100644 --- a/types/node/sqlite.d.ts +++ b/types/node/sqlite.d.ts @@ -158,6 +158,13 @@ declare module "node:sqlite" { */ onConflict?: ((conflictType: number) => number) | undefined; } + interface DeserializeOptions { + /** + * Name of the database to deserialize into. + * @default 'main' + */ + dbName?: string | undefined; + } interface FunctionOptions { /** * If `true`, the [`SQLITE_DETERMINISTIC`](https://www.sqlite.org/c3ref/c_deterministic.html) flag is @@ -445,6 +452,54 @@ declare module "node:sqlite" { * @since v22.5.0 */ open(): void; + /** + * Serializes the database into a binary representation, returned as a + * `Uint8Array`. This is useful for saving, cloning, or transferring an in-memory + * database. This method is a wrapper around [`sqlite3_serialize()`](https://sqlite.org/c3ref/serialize.html). + * + * ```js + * import { DatabaseSync } from 'node:sqlite'; + * + * const db = new DatabaseSync(':memory:'); + * db.exec('CREATE TABLE t(key INTEGER PRIMARY KEY, value TEXT)'); + * db.exec("INSERT INTO t VALUES (1, 'hello')"); + * const buffer = db.serialize(); + * console.log(buffer.length); // Prints the byte length of the database + * ``` + * @since v26.1.0 + * @param dbName Name of the database to serialize. This can be `'main'` + * (the default primary database) or any other database that has been added with + * [`ATTACH DATABASE`](https://www.sqlite.org/lang_attach.html). **Default:** `'main'`. + * @returns A binary representation of the database. + */ + serialize(dbName?: string): NodeJS.NonSharedUint8Array; + /** + * Loads a serialized database into this connection, replacing the current + * database. The deserialized database is writable. Existing prepared statements + * are finalized before deserialization is attempted, even if the operation + * subsequently fails. This method is a wrapper around + * [`sqlite3_deserialize()`](https://sqlite.org/c3ref/deserialize.html). + * + * ```js + * import { DatabaseSync } from 'node:sqlite'; + * + * const original = new DatabaseSync(':memory:'); + * original.exec('CREATE TABLE t(key INTEGER PRIMARY KEY, value TEXT)'); + * original.exec("INSERT INTO t VALUES (1, 'hello')"); + * const buffer = original.serialize(); + * original.close(); + * + * const clone = new DatabaseSync(':memory:'); + * clone.deserialize(buffer); + * console.log(clone.prepare('SELECT value FROM t').get()); + * // Prints: { value: 'hello' } + * ``` + * @since v26.1.0 + * @param buffer A binary representation of a database, such as the + * output of `database.serialize()`. + * @param options Optional configuration for the deserialization. + */ + deserialize(buffer: Uint8Array, options?: DeserializeOptions): void; /** * Compiles a SQL statement into a [prepared statement](https://www.sqlite.org/c3ref/stmt.html). This method is a wrapper * around [`sqlite3_prepare_v2()`](https://www.sqlite.org/c3ref/prepare.html). diff --git a/types/node/stream.d.ts b/types/node/stream.d.ts index 3d39bccf2b1fa6..c9b0811e86479a 100644 --- a/types/node/stream.d.ts +++ b/types/node/stream.d.ts @@ -1,6 +1,7 @@ declare module "node:stream" { import { Blob } from "node:buffer"; import { Abortable, EventEmitter } from "node:events"; + import { ByteReadableStream, toAsyncStreamable } from "node:stream/iter"; import * as promises from "node:stream/promises"; import * as web from "node:stream/web"; class Stream extends EventEmitter { @@ -651,6 +652,37 @@ declare module "node:stream" { * @since v10.0.0 */ [Symbol.asyncIterator](): NodeJS.AsyncIterator; + /** + * When the `--experimental-stream-iter` flag is enabled, `Readable` streams + * implement the `Stream.toAsyncStreamable` protocol, enabling efficient + * consumption by the `stream/iter` API. + * + * This provides a batched async iterator that drains the stream's internal + * buffer into `Uint8Array[]` batches, amortizing the per-chunk Promise overhead + * of the standard `Symbol.asyncIterator` path. For byte-mode streams, chunks + * are yielded directly as `Buffer` instances (which are `Uint8Array` subclasses). + * For object-mode or encoded streams, each chunk is normalized to `Uint8Array` + * before batching. + * + * The returned iterator is tagged as a validated source, so `from()` + * passes it through without additional normalization. + * + * ```js + * import { Readable } from 'node:stream'; + * import { text, from } from 'node:stream/iter'; + * + * const readable = new Readable({ + * read() { this.push('hello'); this.push(null); }, + * }); + * + * // Readable is automatically consumed via toAsyncStreamable + * console.log(await text(from(readable))); // 'hello' + * ``` + * + * Without the `--experimental-stream-iter` flag, calling this method throws + * `ERR_STREAM_ITER_MISSING_FLAG`. + */ + [toAsyncStreamable](): ByteReadableStream; /** * Calls `readable.destroy()` with an `AbortError` and returns * a promise that fulfills when the stream is finished. diff --git a/types/node/stream/iter.d.ts b/types/node/stream/iter.d.ts index 121f78232e9c62..f33decae394100 100644 --- a/types/node/stream/iter.d.ts +++ b/types/node/stream/iter.d.ts @@ -1,4 +1,6 @@ declare module "node:stream/iter" { + import { Abortable } from "node:events"; + import { Readable, Writable } from "node:stream"; // Symbols and custom typedefs const broadcastProtocol: unique symbol; const drainableProtocol: unique symbol; @@ -262,6 +264,154 @@ declare module "node:stream/iter" { */ function from(input: SyncByteReadableStream | SyncShareable, options?: ShareSyncOptions): SyncShare; } + /** + * Converts a classic Readable stream (or duck-typed equivalent) into a + * stream/iter async iterable source that can be passed to `from()`, + * `pull()`, `text()`, etc. + * + * If the object implements the `toAsyncStreamable` protocol (as + * `stream.Readable` does), that protocol is used. Otherwise, the function + * duck-types on `read()` and `on()` (EventEmitter) and wraps the stream with + * a batched async iterator. + * + * The result is cached per instance -- calling `fromReadable()` twice with the + * same stream returns the same iterable. + * + * For object-mode or encoded Readable streams, chunks are automatically + * normalized to `Uint8Array`. + * + * ```js + * import { Readable } from 'node:stream'; + * import { fromReadable, text } from 'node:stream/iter'; + * + * const readable = new Readable({ + * read() { this.push('hello world'); this.push(null); }, + * }); + * + * const result = await text(fromReadable(readable)); + * console.log(result); // 'hello world' + * ``` + * @since v26.1.0 + * @experimental + * @param readable A classic Readable stream or any object + * with `read()` and `on()` methods. + * @returns A stream/iter async iterable source. + */ + function fromReadable(readable: NodeJS.ReadableStream): ByteReadableStream; + interface FromWritableOptions { + backpressure?: BackpressurePolicy | undefined; + } + /** + * Creates a stream/iter Writer adapter from a classic Writable stream (or + * duck-typed equivalent). The adapter can be passed to `pipeTo()` as a + * destination. + * + * Since all writes on a classic Writable are fundamentally asynchronous, + * the synchronous Writer methods (`writeSync`, `writevSync`, `endSync`) always + * return `false` or `-1`, deferring to the async path. The per-write + * `options.signal` parameter from the Writer interface is also ignored. + * + * The result is cached per instance -- calling `fromWritable()` twice with the + * same stream returns the same Writer. + * + * For duck-typed streams that do not expose `writableHighWaterMark`, + * `writableLength`, or similar properties, sensible defaults are used. + * Object-mode writables (if detectable) are rejected since the Writer + * interface is bytes-only. + * + * ```js + * import { Writable } from 'node:stream'; + * import { from, fromWritable, pipeTo } from 'node:stream/iter'; + * + * const writable = new Writable({ + * write(chunk, encoding, cb) { console.log(chunk.toString()); cb(); }, + * }); + * + * await pipeTo(from('hello world'), + * fromWritable(writable, { backpressure: 'block' })); + * ``` + * @since v26.1.0 + * @experimental + * @param writable A classic Writable stream or any object + * with `write()` and `on()` methods. + * @returns A stream/iter Writer adapter. + */ + function fromWritable(writable: NodeJS.WritableStream, options?: FromWritableOptions): Writer; + interface ToReadableOptions extends Abortable { + highWaterMark?: number | undefined; + } + /** + * Creates a byte-mode `stream.Readable` from an `AsyncIterable` + * (the native batch format used by the stream/iter API). Each `Uint8Array` in a + * yielded batch is pushed as a separate chunk into the Readable. + * + * ```js + * import { createWriteStream } from 'node:fs'; + * import { from, pull, toReadable } from 'node:stream/iter'; + * import { compressGzip } from 'node:zlib/iter'; + * + * const source = pull(from('hello world'), compressGzip()); + * const readable = toReadable(source); + * + * readable.pipe(createWriteStream('output.gz')); + * ``` + * @since v26.1.0 + * @experimental + * @param source An `AsyncIterable` source, such as + * the return value of `pull()` or `from()`. + */ + function toReadable(source: Source, options?: ToReadableOptions): Readable; + interface ToReadableSyncOptions { + highWaterMark?: number | undefined; + } + /** + * Creates a byte-mode `stream.Readable` from a synchronous + * `Iterable`. The `_read()` method pulls from the iterator + * synchronously, so data is available immediately via `readable.read()`. + * + * ```js + * import { fromSync, toReadableSync } from 'node:stream/iter'; + * + * const source = fromSync('hello world'); + * const readable = toReadableSync(source); + * + * console.log(readable.read().toString()); // 'hello world' + * ``` + * @since v26.1.0 + * @experimental + * @param source An `Iterable` source, such as the + * return value of `pullSync()` or `fromSync()`. + */ + function toReadableSync(source: SyncSource, options?: ToReadableSyncOptions): Readable; + /** + * Creates a classic `stream.Writable` backed by a stream/iter Writer. + * + * Each `_write()` / `_writev()` call attempts the Writer's synchronous method + * first (`writeSync` / `writevSync`), falling back to the async method if the + * sync path returns `false` or throws. Similarly, `_final()` tries `endSync()` + * before `end()`. When the sync path succeeds, the callback is deferred via + * `queueMicrotask` to preserve the async resolution contract. + * + * The Writable's `highWaterMark` is set to `Number.MAX_SAFE_INTEGER` to + * effectively disable its internal buffering, allowing the underlying Writer + * to manage backpressure directly. + * + * ```js + * import { push, toWritable } from 'node:stream/iter'; + * + * const { writer, readable } = push(); + * const writable = toWritable(writer); + * + * writable.write('hello'); + * writable.end(); + * ``` + * @since v26.1.0 + * @experimental + * @param writer A stream/iter Writer. Only the `write()` method is + * required; `end()`, `fail()`, `writeSync()`, `writevSync()`, `endSync()`, + * and `writev()` are optional. + */ + function toWritable(writer: PartialWriter): Writable; namespace Stream { export { array, diff --git a/types/node/test.d.ts b/types/node/test.d.ts index e3ce6167a0b6af..d8612f6cb97f95 100644 --- a/types/node/test.d.ts +++ b/types/node/test.d.ts @@ -280,6 +280,20 @@ declare module "node:test" { * @default undefined */ shard?: TestShard | undefined; + /** + * Randomize execution order for test files and queued tests. + * This option is not supported with `watch: true`. + * @since v26.1.0 + * @default false + */ + randomize?: boolean | undefined; + /** + * Seed used when randomizing execution order. If this + * option is set, runs can replay the same randomized order deterministically, + * and setting this option also enables randomization. The value must be an + * integer between `0` and `4294967295`. + */ + randomSeed?: number | undefined; /** * A file path where the test runner will * store the state of the tests to allow rerunning only the failed tests on a next run. @@ -336,7 +350,7 @@ declare module "node:test" { functionCoverage?: number | undefined; /** * Specify environment variables to be passed along to the test process. - * This options is not compatible with `isolation='none'`. These variables will override + * This option is not compatible with `isolation='none'`. These variables will override * those from the main process, and are not merged with `process.env`. * @since v25.6.0 * @default process.env @@ -654,6 +668,12 @@ declare module "node:test" { * The nesting level of the test. */ nesting: number; + /** + * A numeric identifier for this test instance, unique + * within the test file's process. Consistent across all events for the same + * test instance, enabling reliable correlation in custom reporters. + */ + testId: number; /** * The ordinal number of the test. */ @@ -676,6 +696,12 @@ declare module "node:test" { * The nesting level of the test. */ nesting: number; + /** + * A numeric identifier for this test instance, unique + * within the test file's process. Consistent across all events for the same + * test instance, enabling reliable correlation in custom reporters. + */ + testId: number; /** * The test type. Either `'suite'` or `'test'`. * @since v22.15.0 @@ -691,6 +717,12 @@ declare module "node:test" { * The nesting level of the test. */ nesting: number; + /** + * A numeric identifier for this test instance, unique + * within the test file's process. Consistent across all events for the same + * test instance, enabling reliable correlation in custom reporters. + */ + testId: number; /** * The test type. Either `'suite'` or `'test'`. * @since v22.15.0 @@ -730,6 +762,12 @@ declare module "node:test" { * The nesting level of the test. */ nesting: number; + /** + * A numeric identifier for this test instance, unique + * within the test file's process. Consistent across all events for the same + * test instance, enabling reliable correlation in custom reporters. + */ + testId: number; /** * The ordinal number of the test. */ @@ -785,6 +823,12 @@ declare module "node:test" { * The nesting level of the test. */ nesting: number; + /** + * A numeric identifier for this test instance, unique + * within the test file's process. Consistent across all events for the same + * test instance, enabling reliable correlation in custom reporters. + */ + testId: number; /** * The ordinal number of the test. */ @@ -817,6 +861,12 @@ declare module "node:test" { * The nesting level of the test. */ nesting: number; + /** + * A numeric identifier for this test instance, unique + * within the test file's process. Consistent across all events for the same + * test instance, enabling reliable correlation in custom reporters. + */ + testId: number; } interface TestStderr { /** @@ -890,6 +940,39 @@ declare module "node:test" { success: boolean; } } + /** + * Returns the {@link TestContext} or {@link SuiteContext} object associated with the + * currently executing test or suite, or `undefined` if called outside of a test or + * suite. This function can be used to access context information from within the + * test or suite function or any async operations within them. + + * ```js + * import { getTestContext } from 'node:test'; + * + * test('example test', async () => { + * const ctx = getTestContext(); + * console.log(`Running test: ${ctx.name}`); + * }); + * + * describe('example suite', () => { + * const ctx = getTestContext(); + * console.log(`Running suite: ${ctx.name}`); + * }); + * ``` + * + * When called from a test, returns a `TestContext`. + * When called from a suite, returns a `SuiteContext`. + * + * If called from outside a test or suite (e.g., at the top level of a module or in + * a setTimeout callback after execution has completed), this function returns + * `undefined`. + * + * When called from within a hook (before, beforeEach, after, afterEach), this + * function returns the context of the test or suite that the hook is associated + * with. + * @since v26.1.0 + */ + function getTestContext(): TestContext | SuiteContext | undefined; /** * An instance of `TestContext` is passed to each test function in order to * interact with the test runner. However, the `TestContext` constructor is not @@ -993,7 +1076,9 @@ declare module "node:test" { */ readonly error: EventData.Error | null; /** - * Number of times the test has been attempted. + * The attempt number of the test. This value is zero-based, so the first attempt is `0`, + * the second attempt is `1`, and so on. This property is useful in conjunction with the + * `--test-rerun-failures` option to determine which attempt the test is currently running. * @since v21.7.0, v20.12.0 */ readonly attempt: number; @@ -1294,6 +1379,31 @@ declare module "node:test" { * @since v18.7.0, v16.17.0 */ readonly signal: AbortSignal; + /** + * Indicates whether the suite and all of its subtests have passed. + * @since v26.1.0 + */ + readonly passed: boolean; + /** + * The attempt number of the suite. This value is zero-based, so the first attempt is `0`, + * the second attempt is `1`, and so on. This property is useful in conjunction with the + * `--test-rerun-failures` option to determine the attempt number of the current run. + * @since v26.1.0 + */ + readonly attempt: number; + /** + * Output a diagnostic message. This is typically used for logging information + * about the current suite or its tests. + * + * ```js + * test.describe('my suite', (suite) => { + * suite.diagnostic('Suite diagnostic message'); + * }); + * ``` + * @since v26.1.0 + * @param message A diagnostic message to output. + */ + diagnostic(message: string): void; } interface TestOptions { /** diff --git a/types/node/ts5.6/index.d.ts b/types/node/ts5.6/index.d.ts index 83f660488b56e7..b2e24a8989f0cd 100644 --- a/types/node/ts5.6/index.d.ts +++ b/types/node/ts5.6/index.d.ts @@ -68,6 +68,7 @@ /// /// /// +/// /// /// /// diff --git a/types/node/ts5.7/index.d.ts b/types/node/ts5.7/index.d.ts index d296cc6151a449..a97cc1a1bce5af 100644 --- a/types/node/ts5.7/index.d.ts +++ b/types/node/ts5.7/index.d.ts @@ -68,6 +68,7 @@ /// /// /// +/// /// /// /// diff --git a/types/node/util.d.ts b/types/node/util.d.ts index f6da4ee7d103cb..e6d87ff543a7ea 100644 --- a/types/node/util.d.ts +++ b/types/node/util.d.ts @@ -974,6 +974,8 @@ declare module "node:util" { * `reason`. * * ```js + * import util from 'node:util'; + * * function fn() { * return Promise.reject(null); * } @@ -1246,13 +1248,28 @@ declare module "node:util" { * * The special format value `none` applies no additional styling to the text. * + * In addition to predefined color names, `util.styleText()` supports hex color + * strings using ANSI TrueColor (24-bit) escape sequences. Hex colors can be + * specified in either 3-digit (`#RGB`) or 6-digit (`#RRGGBB`) format: + * + * ```js + * import { styleText } from 'node:util'; + * + * // 6-digit hex color + * console.log(styleText('#ff5733', 'Orange text')); + * + * // 3-digit hex color (shorthand) + * console.log(styleText('#f00', 'Red text')); + * ``` + * * The full list of formats can be found in [modifiers](https://nodejs.org/docs/latest-v26.x/api/util.html#modifiers). - * @param format A text format or an Array of text formats defined in `util.inspect.colors`. + * @param format A text format or an Array of text formats defined in `util.inspect.colors`, or a hex color in `#RGB` + * or `#RRGGBB` form. * @param text The text to to be formatted. * @since v20.12.0 */ export function styleText( - format: InspectColor | readonly InspectColor[], + format: InspectColor | readonly InspectColor[] | `#${string}`, text: string, options?: StyleTextOptions, ): string; diff --git a/types/node/v8.d.ts b/types/node/v8.d.ts index b3e5e71ee0fcb0..ea42d7bcdd66b3 100644 --- a/types/node/v8.d.ts +++ b/types/node/v8.d.ts @@ -412,6 +412,21 @@ declare module "node:v8" { */ [Symbol.dispose](): void; } + /** + * @since v26.1.0 + */ + interface SyncHeapProfileHandle { + /** + * Stopping collecting the profile and return the profile data. + * @since v26.1.0 + */ + stop(): string; + /** + * Stopping collecting the profile and the profile will be discarded. + * @since v26.1.0 + */ + [Symbol.dispose](): void; + } /** * @since v24.8.0 */ @@ -444,18 +459,85 @@ declare module "node:v8" { */ [Symbol.asyncDispose](): Promise; } + interface CPUProfileOptions { + /** + * Requested sampling interval in milliseconds. **Default:** `0`. + */ + sampleInterval?: number | undefined; + /** + * Maximum number of samples to keep before older + * entries are discarded. **Default:** `4294967295`. + */ + maxBufferSize?: number | undefined; + } /** * Starting a CPU profile then return a `SyncCPUProfileHandle` object. * This API supports `using` syntax. * * ```js - * const handle = v8.startCpuProfile(); + * const handle = v8.startCpuProfile({ sampleInterval: 1, maxBufferSize: 10_000 }); * const profile = handle.stop(); * console.log(profile); * ``` * @since v25.0.0 */ - function startCpuProfile(): SyncCPUProfileHandle; + function startCpuProfile(options?: CPUProfileOptions): SyncCPUProfileHandle; + interface HeapProfileOptions { + /** + * The average sampling interval in bytes. + * **Default:** `524288` (512 KiB). + */ + sampleInterval?: number | undefined; + /** + * The maximum stack depth for samples. + * **Default:** `16`. + */ + stackDepth?: number | undefined; + /** + * Force garbage collection before taking the profile. + * **Default:** `false`. + */ + forceGC?: boolean | undefined; + /** + * Include objects collected + * by major GC. **Default:** `false`. + */ + includeObjectsCollectedByMajorGC?: boolean | undefined; + /** + * Include objects collected + * by minor GC. **Default:** `false`. + */ + includeObjectsCollectedByMinorGC?: boolean | undefined; + } + /** + * Starting a heap profile then return a `SyncHeapProfileHandle` object. + * This API supports `using` syntax. + * + * ```js + * import v8 from 'node:v8'; + * + * const handle = v8.startHeapProfile(); + * const profile = handle.stop(); + * console.log(profile); + * ``` + * + * With custom parameters: + * + * ```js + * import v8 from 'node:v8'; + * + * const handle = v8.startHeapProfile({ + * sampleInterval: 1024, + * stackDepth: 8, + * forceGC: true, + * includeObjectsCollectedByMajorGC: true, + * }); + * const profile = handle.stop(); + * console.log(profile); + * ``` + * @since v26.1.0 + */ + function startHeapProfile(options?: HeapProfileOptions): SyncHeapProfileHandle; /** * V8 only supports `Latin-1/ISO-8859-1` and `UTF16` as the underlying representation of a string. * If the `content` uses `Latin-1/ISO-8859-1` as the underlying representation, this function will return true; diff --git a/types/node/worker_threads.d.ts b/types/node/worker_threads.d.ts index 38b5020723cff1..f2804eae3dcc37 100644 --- a/types/node/worker_threads.d.ts +++ b/types/node/worker_threads.d.ts @@ -10,7 +10,7 @@ declare module "node:worker_threads" { import { Readable, Writable } from "node:stream"; import { ReadableStream, TransformStream, WritableStream } from "node:stream/web"; import { URL } from "node:url"; - import { CPUProfileHandle, HeapInfo, HeapProfileHandle } from "node:v8"; + import { CPUProfileHandle, CPUProfileOptions, HeapInfo, HeapProfileHandle, HeapProfileOptions } from "node:v8"; import { Context } from "node:vm"; import { MessageEvent } from "undici-types"; const isInternalThread: boolean; @@ -259,7 +259,7 @@ declare module "node:worker_threads" { * `, { eval: true }); * * worker.on('online', async () => { - * const handle = await worker.startCpuProfile(); + * const handle = await worker.startCpuProfile({ sampleInterval: 1 }); * const profile = await handle.stop(); * console.log(profile); * worker.terminate(); @@ -283,16 +283,16 @@ declare module "node:worker_threads" { * ``` * @since v24.8.0 */ - startCpuProfile(): Promise; + startCpuProfile(options?: CPUProfileOptions): Promise; /** * Starting a Heap profile then return a Promise that fulfills with an error * or an `HeapProfileHandle` object. This API supports `await using` syntax. * * ```js - * const { Worker } = require('node:worker_threads'); + * import { Worker } from 'node:worker_threads'; * * const worker = new Worker(` - * const { parentPort } = require('worker_threads'); + * const { parentPort } = require('node:worker_threads'); * parentPort.on('message', () => {}); * `, { eval: true }); * @@ -307,7 +307,7 @@ declare module "node:worker_threads" { * `await using` example. * * ```js - * const { Worker } = require('node:worker_threads'); + * import { Worker } from 'node:worker_threads'; * * const w = new Worker(` * const { parentPort } = require('node:worker_threads'); @@ -319,8 +319,9 @@ declare module "node:worker_threads" { * await using handle = await w.startHeapProfile(); * }); * ``` + * @since v24.9.0 */ - startHeapProfile(): Promise; + startHeapProfile(options?: HeapProfileOptions): Promise; /** * Calls `worker.terminate()` when the dispose scope is exited. * diff --git a/types/readable-stream/index.d.ts b/types/readable-stream/index.d.ts index f4cb11737312ed..e31db99c2f6699 100644 --- a/types/readable-stream/index.d.ts +++ b/types/readable-stream/index.d.ts @@ -8,14 +8,22 @@ declare class StringDecoder { end(buffer?: Buffer): string; } -type Is = T; -declare var NoAsyncDispose: { - new( - ...arguments: any[] - ): typeof globalThis.Symbol extends { readonly asyncDispose: Is } - ? symbol extends S ? {} : { [P in S]: never } - : {}; -}; +// These fairly ugly hacks are to ensure that readable-stream's Readable is +// assignable to @types/node's Readable for convenience. readable-stream 4.x is +// derived from Node.js 18.x, so these interfaces diverge if using more recent +// versions of @types/node. +type WellKnownSymbols = { + [K in keyof SymbolConstructor]: SymbolConstructor[K] extends symbol + ? symbol extends SymbolConstructor[K] ? never : SymbolConstructor[K] + : never; +}[keyof SymbolConstructor]; +declare var SymbolAsyncDispose: SymbolConstructor extends { readonly asyncDispose: infer S extends symbol } ? S : never; +type NoAsyncDispose = typeof SymbolAsyncDispose extends never ? {} : { [SymbolAsyncDispose]: never }; +declare var StreamToAsyncStreamable: Exclude< + keyof NodeStream.Readable & symbol, + keyof NodeJS.EventEmitter | WellKnownSymbols +>; +type NoToAsyncStreamable = typeof StreamToAsyncStreamable extends never ? {} : { [StreamToAsyncStreamable]: never }; // forward-compatible iterator type for TS <5.6 declare global { @@ -102,7 +110,7 @@ interface _IReadable extends _IEventEmitter { destroy(error?: Error): this; } -declare class _Readable extends NoAsyncDispose implements _IReadable { +declare class _Readable implements _IReadable { readable: boolean; readonly readableFlowing: boolean | null; readonly readableHighWaterMark: number; @@ -242,6 +250,7 @@ declare class _Readable extends NoAsyncDispose implements _IReadable { _undestroy(): void; } +interface _Readable extends NoAsyncDispose, NoToAsyncStreamable {} declare namespace _Readable { // ==== BufferList ==== From e186cd854fef1fbd5152877e78f9ab05743c226e Mon Sep 17 00:00:00 2001 From: Tyoneb <59046401+Tyoneb@users.noreply.github.com> Date: Wed, 1 Jul 2026 12:27:10 +0200 Subject: [PATCH 6/6] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#75184=20[tabul?= =?UTF-8?q?ator-tables]=20Fix=20`download`=20method=20signature=20by=20@Ty?= =?UTF-8?q?oneb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Benoit CHOMEL --- types/tabulator-tables/index.d.ts | 36 ++++++++++++++++++- .../tabulator-tables-tests.ts | 24 +++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/types/tabulator-tables/index.d.ts b/types/tabulator-tables/index.d.ts index 8a39ef9e74598b..408e262a23c681 100755 --- a/types/tabulator-tables/index.d.ts +++ b/types/tabulator-tables/index.d.ts @@ -1150,6 +1150,36 @@ export interface AdditionalExportOptions { formatCells?: boolean | undefined; } +export interface ExportRow { + /** The type of row. */ + type: "header" | "group" | "calc" | "row"; + /** + * An array of `ExportColumn` objects representing the columns on the row. + * + * In the case of tables with column groups this array can also include `null` values representing spaces where columns would have been if not for a neighbouring column taking up multiple columns or rows, such as a column group header. These `null` values are included to help deal with rowspan and colspan alignment and in most cases can be ignored. An example of where they can come in useful can be found in the built-in xlsx downloader. + */ + columns: (ExportColumn | null)[]; + /** The Component Object for the row or group that the `ExportRow` represents. */ + component: RowComponent; + /** If the row is either a group or a data tree child, this value contains an integer representing which level the row is on, the greater the number the more indented the row should be. */ + indent: number; +} + +export interface ExportColumn { + /** The Component Object for the column that the `ExportColumn` represent. */ + component: ColumnComponent; + /** This usually has a value of 1, in the case of grouped column headers, this shows how many levels of child columns the group has. */ + depth: number; + /** The height of the cell in rows, generally this has a value of 1, but when dealing with grouped column headers this describes how rows hight the cell should be to allow for neighboring grouped column headers. */ + height: number; + /** The value of the cell or title of the column header. */ + value: any; + /** The width in columns, generally this has a value of 1, but when dealing with grouped column headers this describes how many columns wide the column group should be, in the case of group headers this shows as the number of columns in the table to ensure the group header is full width. */ + width: number; + /** The column identifier. */ + field: string; +} + export interface OptionsLocale { /** You can set the current local in one of two ways. If you want to set it when the table is created, simply include the locale option in your Tabulator constructor. You can either pass in a string matching one of the language options you have defined, or pass in the boolean true which will cause Tabulator to auto-detect the browsers language settings from the navigator.language object. */ locale?: boolean | string | undefined; @@ -2833,7 +2863,11 @@ declare class Tabulator { download: ( downloadType: | DownloadType - | ((columns: ColumnDefinition[], data: any, options: any, setFileContents: any) => any), + | (( + rows: ExportRow[], + options: any, + setFileContents: (fileContents: any, mimeType: string) => void, + ) => any), fileName: string, params?: DownloadOptions, filter?: RowRangeLookup, diff --git a/types/tabulator-tables/tabulator-tables-tests.ts b/types/tabulator-tables/tabulator-tables-tests.ts index e142073ecccdd5..7cca3fd8d3e44f 100644 --- a/types/tabulator-tables/tabulator-tables-tests.ts +++ b/types/tabulator-tables/tabulator-tables-tests.ts @@ -639,6 +639,30 @@ table.download("pdf", "data.pdf", { table.download("xlsx", "AllData.xlsx"); table.download("csv", "data.csv", { bom: true }); table.download("csv", "data.csv", { delimiter: "." }); +table.download( + (rows, options, setFileContents) => { + const fileContents: string[] = []; + rows.forEach((row) => { + const item: any[] = []; + switch (row.type) { + case "header": + case "group": + case "calc": + case "row": + row.columns.forEach((col) => { + if (col) { + item.push(col.value); + } + fileContents.push(item.join(options.delimiter)); + }); + break; + } + }); + setFileContents(fileContents.join("\r\n"), "text/plain"); + }, + "data.txt", + { delimiter: "." }, +); // 4.4 updates table.moveColumn("name", "age", true);