diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 00000000..94fe2f92 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,100 @@ +name: CI + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + haxe_ver: [4.0.5, 4.3.7, latest] + + steps: + - uses: actions/checkout@v7 + + - uses: krdlab/setup-haxe@v2 + with: + haxe-version: ${{ matrix.haxe_ver }} + + - run: haxelib dev hxnodejs . + name: Set haxelib dev path + + - run: | + haxe build.hxml + haxelib git dox https://github.com/HaxeFoundation/dox + haxe doc.hxml + name: Build + + - name: Upload artifact + if: matrix.haxe_ver == 'latest' + uses: actions/upload-pages-artifact@v3 + with: + path: ./bin/api + + test: + strategy: + fail-fast: false + matrix: + haxe_ver: [4.3.7, latest] + runner: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.runner }} + steps: + - uses: actions/checkout@v7 + + - uses: krdlab/setup-haxe@v2 + with: + haxe-version: ${{ matrix.haxe_ver }} + + - uses: actions/setup-node@v4 + if: matrix.runner == 'windows-latest' + with: + node-version: 24 + + - run: haxelib dev hxnodejs . + name: Set haxelib dev path + + - name: Get Haxe commit SHA + id: haxe_sha + shell: bash + env: + GH_TOKEN: ${{ github.token }} + run: | + version=$(haxe --version) + echo "Haxe version: $version" + short_sha=${version##*+} + full_sha=$(gh api repos/HaxeFoundation/haxe/commits/$short_sha --jq '.sha') + echo "Commit SHA: $short_sha, Full SHA: $full_sha" + echo "sha=$full_sha" >> "$GITHUB_OUTPUT" + + - uses: actions/checkout@v7 + with: + repository: HaxeFoundation/haxe + path: haxe + ref: ${{ steps.haxe_sha.outputs.sha }} + + - name: Test + shell: bash + run: | + if [[ "${{ matrix.runner }}" == "macos-latest" ]]; then + echo "" > sys/compile-fs.hxml + fi + haxe --run RunCi js + working-directory: haxe/tests + + deploy: + needs: [build, test] + if: github.ref == 'refs/heads/master' && github.event_name == 'push' + runs-on: ubuntu-latest + permissions: + contents: read + pages: write + id-token: write + + environment: + name: github-pages + url: ${{steps.deployment.outputs.page_url}} + steps: + - name: Deploy artifact + id: deployment + uses: actions/deploy-pages@v4 + diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 27009ef6..00000000 --- a/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -language: haxe -dist: xenial - -haxe: - - 3.4.7 - - development - -install: - haxelib dev hxnodejs . - -script: - - haxe build.hxml - - haxelib git dox https://github.com/HaxeFoundation/dox - - haxe doc.hxml - -deploy: - provider: script - script: haxe deploy.hxml - on: - branch: master - haxe: development - condition: $TRAVIS_EVENT_TYPE != "cron" - skip_cleanup: true diff --git a/HOWTO.md b/HOWTO.md index 0dca3da0..d98aab23 100644 --- a/HOWTO.md +++ b/HOWTO.md @@ -72,14 +72,14 @@ Node.js event emitters take strings as event names and don't check listener sign If you provide an instance of `Event` abstract string type where an event name is expected in any `EventEmitter` method, then the listener type will be unified with `T` and thus provide type checking and inference for the listener function. -We provide [@:enum abstract types](http://haxe.org/manual/types-abstract-enum.html) that enumerate possible event names for a given event emitter. They are implicitly castable to `Event` and can be used for type-checking listener functions as described above. For each `EventEmitter` subclass, an `@:enum abstract` type must be created with a `Event` postfix in its name. For example, if we have a `Process` class which is an `EventEmitter`, it should have a pairing `ProcessEvent` type in its module, i.e.: +We provide [enum abstract types](https://haxe.org/manual/types-abstract-enum.html) that enumerate possible event names for a given event emitter. They are implicitly castable to `Event` and can be used for type-checking listener functions as described above. For each `EventEmitter` subclass, an `enum abstract` type must be created with a `Event` postfix in its name. For example, if we have a `Process` class which is an `EventEmitter`, it should have a pairing `ProcessEvent` type in its module, i.e.: ```haxe extern class Process extends EventEmitter { // ... } -@:enum abstract ProcessEvent(Event) to Event { +enum abstract ProcessEvent(Event) to Event { var Exit : ProcessEventVoid> = "exit"; } ``` @@ -96,7 +96,7 @@ TODO (describe the difference of overloading/optional argument concepts and advi The whole idea of haxe externs is provide a fully type-checked access to external API. Considering that, we must avoid the need for use `Dynamic` type or `cast` and think of a way to properly express type restrictions. -On the other hand, we want developers to be able to copy-paste node.js code into haxe with minimal modification and have it compiling. For that reason we have to weaken some typing restrictions, for example adding implicit cast `from String` for our `@:enum abstract` types. +On the other hand, we want developers to be able to copy-paste node.js code into haxe with minimal modification and have it compiling. For that reason we have to weaken some typing restrictions, for example adding implicit cast `from String` for our `enum abstract` types. ### Multiple inheritance @@ -147,12 +147,12 @@ If a type can be of 3 and more types, nested `EitherType` can be used. ### Constant enumeration -If there's a finite set of posible values for a function argument or object field, [@:enum abstract types](http://haxe.org/manual/types-abstract-enum.html) are used to enumerate those values. +If there's a finite set of posible values for a function argument or object field, [enum abstract types](https://haxe.org/manual/types-abstract-enum.html) are used to enumerate those values. Example: ```haxe -@:enum abstract SymlinkType(String) from String to String { +enum abstract SymlinkType(String) from String to String { var File = "file"; var Dir = "dir"; var Junction = "junction"; @@ -164,10 +164,10 @@ The `to` and `from` implicit cast must be added so user can use both enumeration Constant names are `UpperCamelCase` and their values are actual values expected by native API. -Note that combined with `haxe.EitherType` (described above), `@:enum abstract`s can handle even complicated cases where a value can be of different types, e.g. +Note that combined with `haxe.EitherType` (described above), `enum abstract`s can handle even complicated cases where a value can be of different types, e.g. ```haxe -@:enum abstract ListeningEventAddressType(haxe.EitherType) to haxe.EitherType { +enum abstract ListeningEventAddressType(haxe.EitherType) to haxe.EitherType { var TCPv4 = 4; var TCPv6 = 6; var Unix = -1; @@ -213,4 +213,4 @@ extern class NotSoDeprecated { ## Tricks and hints -TODO (dealing with keywords, `untyped __js__`, inline methods and properties on extern classes) +TODO (dealing with keywords, `js.Syntax.code`, inline methods and properties on extern classes) diff --git a/ImportAll.hx b/ImportAll.hx index fc2f4742..dc655e2e 100644 --- a/ImportAll.hx +++ b/ImportAll.hx @@ -24,6 +24,10 @@ class ImportAll { Context.getType(typePath); } } + #if haxe5 + Context.onAfterInitMacros(() -> loop([])); + #else loop([]); + #end } } diff --git a/README.md b/README.md index 984468b0..ab9c921e 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,13 @@ # Haxe Node.JS -[![Build Status](https://badgen.net/travis/HaxeFoundation/hxnodejs?label=build)](https://travis-ci.org/HaxeFoundation/hxnodejs) +[![Build Status](https://img.shields.io/github/actions/workflow/status/HaxeFoundation/hxnodejs/main.yml?branch=master&label=build)](https://github.com/HaxeFoundation/hxnodejs/actions/workflows/main.yml) [![Haxelib Version](https://badgen.net/haxelib/v/hxnodejs)](https://lib.haxe.org/p/hxnodejs) [![Haxelib Downloads](https://badgen.net/haxelib/d/hxnodejs?color=blue)](https://lib.haxe.org/p/hxnodejs) [![Haxelib License](https://badgen.net/haxelib/license/hxnodejs)](LICENSE.md) -Extern type definitions for Node.JS. Haxe **3.4** or newer is required. +Extern type definitions for Node.JS. Haxe **4.0** or newer is required. +Targeted at **Node.js 24** Active LTS APIs (bindings may lag behind edge cases). Haxe-generated API documentation is available at http://haxefoundation.github.io/hxnodejs/js/Node.html. diff --git a/ci/Config.hx b/ci/Config.hx deleted file mode 100644 index b082fba0..00000000 --- a/ci/Config.hx +++ /dev/null @@ -1,9 +0,0 @@ -import Utils.*; - -class Config { - static public var htmlDir = env("GHP_HTMLDIR", "bin/api"); - static public var remote = env("GHP_REMOTE", null); // should be in the form of https://token@github.com/account/repo.git - static public var branch = env("GHP_BRANCH", "gh-pages"); - static public var username = env("GHP_USERNAME", null); - static public var email = env("GHP_EMAIL", null); -} diff --git a/ci/DeployGhPages.hx b/ci/DeployGhPages.hx deleted file mode 100644 index d3282e29..00000000 --- a/ci/DeployGhPages.hx +++ /dev/null @@ -1,45 +0,0 @@ -import Sys.*; -import Utils.*; -import Config.*; - -using StringTools; - -class DeployGhPages { - static function main():Void { - var root = getCwd(); - - if (remote == null) { - println('GHP_REMOTE is not set, skip deploy.'); - return; - } - - // TravisCI by default clones repositories to a depth of 50 commits. - // We need a full clone inorder to do git operations. - runCommand("git", ["fetch", "--unshallow"]); - - var sha = commandOutput("git", ["rev-parse", "HEAD"]).trim(); - - setCwd(htmlDir); - runCommand("git", ["init"]); - if (username != null) - runCommand("git", ["config", "--local", "user.name", username]); - if (email != null) - runCommand("git", ["config", "--local", "user.email", email]); - runCommand("git", ["remote", "add", "local", root]); - runCommand("git", ["remote", "add", "remote", remote]); - runCommand("git", ["fetch", "--all"]); - runCommand("git", ["checkout", "--orphan", branch]); - if (commandOutput("git", ["ls-remote", "--heads", "local", branch]).trim() != "") { - runCommand("git", ["reset", "--soft", 'local/${branch}']); - } - if (commandOutput("git", ["ls-remote", "--heads", "remote", branch]).trim() != "") { - runCommand("git", ["reset", "--soft", 'remote/${branch}']); - } - runCommand("git", ["add", "--all"]); - runCommand("git", ["commit", "--allow-empty", "--quiet", "-m", 'deploy for ${sha}']); - runCommand("git", ["push", "local", branch]); - - setCwd(root); - runCommand("git", ["push", remote, branch]); - } -} diff --git a/ci/Utils.hx b/ci/Utils.hx deleted file mode 100644 index 73e77176..00000000 --- a/ci/Utils.hx +++ /dev/null @@ -1,62 +0,0 @@ -import Sys.*; -import sys.io.*; -import sys.FileSystem.*; -import haxe.io.*; - -class Utils { - static public function env(name:String, def:String):String { - return switch (getEnv(name)) { - case null: - def; - case v: - v; - } - } - - static public function runCommand(cmd:String, args:Array):Void { - println('run: $cmd $args'); - switch (command(cmd, args)) { - case 0: - // pass - case exitCode: - exit(exitCode); - } - } - - static public function commandOutput(cmd:String, args:Array):String { - var p = new Process(cmd, args); - var exitCode = p.exitCode(); - var output = p.stdout.readAll().toString(); - p.close(); - if (exitCode != 0) - exit(exitCode); - return output; - } - - static public function copyRecursive(src:String, dest:String):Void { - if (isDirectory(src)) { - createDirectory(dest); - for (item in readDirectory(src)) { - var srcPath = Path.join([src, item]); - var destPath = Path.join([dest, item]); - copyRecursive(srcPath, destPath); - } - } else { - File.copy(src, dest); - } - } - - static public function deleteRecursive(path:String):Void { - if (!exists(path)) - return; - - if (isDirectory(path)) { - for (item in readDirectory(path)) { - deleteRecursive(Path.join([path, item])); - } - deleteDirectory(path); - } else { - deleteFile(path); - } - } -} diff --git a/deploy.hxml b/deploy.hxml deleted file mode 100644 index cc9859db..00000000 --- a/deploy.hxml +++ /dev/null @@ -1,2 +0,0 @@ --cp ci ---run DeployGhPages \ No newline at end of file diff --git a/examples/AssertThrows.hx b/examples/AssertThrows.hx index 46be5d26..4074d7c5 100644 --- a/examples/AssertThrows.hx +++ b/examples/AssertThrows.hx @@ -1,16 +1,17 @@ -#if haxe4 import js.lib.Error; import js.lib.RegExp; -#else -import js.Error; -import js.RegExp; -#end import js.node.Assert; class AssertThrows { static function main() { Assert.throws(function() throw new Error("Wrong value"), Error); Assert.throws(function() throw new Error("Wrong value"), new RegExp("value")); - Assert.throws(function() throw new Error("Wrong value"), function(err) return (Std.is(err, Error) && ~/value/.match(err.message)), "unexpected error"); + Assert.throws(function() throw new Error("Wrong value"), function(err) + return switch Std.downcast(cast err, Error) { + case null: false; + case e: ~/value/.match(e.message); + }, + "unexpected error" + ); } } diff --git a/examples/StreamExample.hx b/examples/StreamExample.hx index 283eb377..5e82b077 100644 --- a/examples/StreamExample.hx +++ b/examples/StreamExample.hx @@ -31,7 +31,8 @@ class StreamExample { } catch (er:Error) { // uh oh! bad json! res.statusCode = 400; - return res.end('error: ' + er.message); + res.end('error: ' + er.message); + return; } // write back something interesting to the user: diff --git a/haxelib.json b/haxelib.json index f03be13b..7ec06077 100644 --- a/haxelib.json +++ b/haxelib.json @@ -4,7 +4,7 @@ "description": "Extern definitions for node.js", "license": "MIT", "version": "12.2.0", - "releasenote": "Update some API, fix some deprecation warnings.", + "releasenote": "Node.js 24 Active LTS audit ongoing; Haxe 4.0+ only.", "classPath": "src", "contributors": ["nadako", "Simn", "Gama11", "HaxeFoundation"], "tags": ["js", "nodejs", "async", "net", "web", "extern"] diff --git a/src/Sys.hx b/src/Sys.hx index e423a65d..68a8ac69 100644 --- a/src/Sys.hx +++ b/src/Sys.hx @@ -82,18 +82,14 @@ class Sys { return process.uptime(); } - #if (haxe_ver >= 3.3) @:deprecated("Use programPath instead") - #end public static inline function executablePath():String { return process.argv[0]; } - #if (haxe_ver >= 3.3) public static inline function programPath():String { return js.Node.__filename; } - #end public static function getChar(echo:Bool):Int { throw "Sys.getChar is currently not implemented on node.js"; @@ -132,7 +128,7 @@ private class FileOutput extends haxe.io.Output { return Fs.writeSync(fd, Buffer.hxFromBytes(s), pos, len); } - override public function writeString(s:String #if (haxe_ver >= 4), ?encoding:haxe.io.Encoding #end) { + override public function writeString(s:String, ?encoding:haxe.io.Encoding) { Fs.writeSync(fd, s); } @@ -154,6 +150,7 @@ private class FileInput extends haxe.io.Input { override public function readByte():Int { var buf = Buffer.alloc(1); + // TODO(section-2): typed Node ErrnoException instead of Dynamic catch try { Fs.readSync(fd, buf, 0, 1, null); } catch (e:Dynamic) { @@ -167,6 +164,7 @@ private class FileInput extends haxe.io.Input { override public function readBytes(s:Bytes, pos:Int, len:Int):Int { var buf = Buffer.hxFromBytes(s); + // TODO(section-2): typed Node ErrnoException instead of Dynamic catch try { return Fs.readSync(fd, buf, pos, len, null); } catch (e:Dynamic) { diff --git a/src/_internal/SuppressDeprecated.hx b/src/_internal/SuppressDeprecated.hx index 1671aec1..4d781c06 100644 --- a/src/_internal/SuppressDeprecated.hx +++ b/src/_internal/SuppressDeprecated.hx @@ -6,7 +6,6 @@ import haxe.macro.Context; @:noCompletion class SuppressDeprecated { public static function run() { - #if haxe4 Context.onAfterTyping(function(_) { Context.filterMessages(x -> switch x { case Warning(msg, pos) if (~/js\/node\/Url\.hx$/.match(Context.getPosInfos(pos).file)): @@ -17,7 +16,6 @@ class SuppressDeprecated { true; }); }); - #end } } #end diff --git a/src/js/Node.hx b/src/js/Node.hx index 9e7f23ed..d49e6fc5 100644 --- a/src/js/Node.hx +++ b/src/js/Node.hx @@ -24,14 +24,20 @@ package js; import haxe.Constraints.Function; import haxe.extern.Rest; +import js.Syntax.code; +import js.lib.Promise; import js.node.Module; import js.node.Process; import js.node.Timers.Immediate; import js.node.Timers.Timeout; import js.node.console.Console; -#if haxe4 -import js.Syntax.code; -#end +import js.node.perf_hooks.Performance; +import js.node.url.URL; +import js.node.web.Navigator as WebNavigator; +import js.node.web.Request; +import js.node.web.Request.RequestInit; +import js.node.web.Response; +import js.node.web.Storage as WebStorage; /** Node.js globals @@ -44,11 +50,7 @@ extern class Node { static var __dirname(get, never):String; private static inline function get___dirname():String { - #if haxe4 return code("__dirname"); - #else - return untyped __js__("__dirname"); - #end } /** @@ -57,11 +59,7 @@ extern class Node { static var __filename(get, never):String; private static inline function get___filename():String { - #if haxe4 return code("__filename"); - #else - return untyped __js__("__filename"); - #end } /** @@ -85,11 +83,7 @@ extern class Node { static var console(get, never):Console; private static inline function get_console():Console { - #if haxe4 return code("console"); - #else - return untyped __js__("console"); - #end } /** @@ -98,32 +92,84 @@ extern class Node { static var exports(get, never):Dynamic; private static inline function get_exports():Dynamic { - #if haxe4 return code("exports"); - #else - return untyped __js__("exports"); - #end } + /** + Browser-compatible `fetch()` (undici). + + @see https://nodejs.org/api/globals.html#fetch + **/ + @:overload(function(input:Request, ?init:RequestInit):Promise {}) + @:overload(function(input:URL, ?init:RequestInit):Promise {}) + static function fetch(input:String, ?init:RequestInit):Promise; + /** In browsers, the top-level scope is the global scope. This means that within the browser `var something` will define a new global variable. In Node.js this is different. The top-level scope is not the global scope; `var something` inside a Node.js module will be local to that module. + + Stability: 3 - Legacy. Use `globalThis` instead. **/ static inline var global:Dynamic = cast Node; + /** + `globalThis` is the universal way to access the global object. + + @see https://nodejs.org/api/globals.html#globalthis + **/ + static var globalThis(get, never):Dynamic; + + private static inline function get_globalThis():Dynamic { + return code("globalThis"); + } + + /** + Web Storage API `localStorage`. + + Stability: 1.2 - Release candidate. Enable with `--experimental-webstorage`. + Persists to the file given by `--localstorage-file`. + + @see https://nodejs.org/api/globals.html#localstorage + **/ + static var localStorage(get, never):WebStorage; + + private static inline function get_localStorage():WebStorage { + return code("localStorage"); + } + /** This variable may appear to be global but is not. See [module](https://nodejs.org/api/modules.html#modules_module). **/ static var module(get, never):Module; private static inline function get_module():Module { - #if haxe4 return code("module"); - #else - return untyped __js__("module"); - #end + } + + /** + A partial browser-compatible `Navigator` implementation. + + @see https://nodejs.org/api/globals.html#navigator + **/ + static var navigator(get, never):WebNavigator; + + private static inline function get_navigator():WebNavigator { + return code("navigator"); + } + + /** + An object that can be used to collect performance metrics from the current Node.js instance. + It is similar to `window.performance` in browsers. + + @see https://nodejs.org/api/globals.html#performance + @see https://nodejs.org/api/perf_hooks.html#perf_hooksperformance + **/ + static var performance(get, never):Performance; + + private static inline function get_performance():Performance { + return code("performance"); } /** @@ -132,11 +178,7 @@ extern class Node { static var process(get, never):Process; private static inline function get_process():Process { - #if haxe4 return code("process"); - #else - return untyped __js__("process"); - #end } /** @@ -153,11 +195,20 @@ extern class Node { This variable may appear to be global but is not. See [require()](https://nodejs.org/api/modules.html#modules_require_id). **/ static inline function require(module:String):Dynamic { - #if haxe4 return code("require({0})", module); - #else - return untyped __js__("require({0})", module); - #end + } + + /** + Web Storage API `sessionStorage`. + + Stability: 1.2 - Release candidate. Enable with `--experimental-webstorage`. + + @see https://nodejs.org/api/globals.html#sessionstorage + **/ + static var sessionStorage(get, never):WebStorage; + + private static inline function get_sessionStorage():WebStorage { + return code("sessionStorage"); } /** @@ -174,8 +225,25 @@ extern class Node { `setTimeout` is described in the [timers](https://nodejs.org/api/timers.html) section. **/ static function setTimeout(callback:Function, delay:Int, args:Rest):Timeout; + + /** + The WHATWG [`structuredClone`](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone) method. + + @see https://nodejs.org/api/globals.html#structuredclonevalue-options + **/ + static function structuredClone(value:Dynamic, ?options:StructuredCloneOptions):Dynamic; +} + +/** + Options for `Node.structuredClone`. +**/ +typedef StructuredCloneOptions = { + /** + A list of transferable objects that will be moved rather than cloned. + **/ + @:optional var transfer:Array; } -@:deprecated typedef TimeoutObject = js.node.Timers.Timeout; -@:deprecated typedef IntervalObject = js.node.Timers.Timeout; -@:deprecated typedef ImmediateObject = js.node.Timers.Immediate; +@:deprecated("Use Timeout instead") typedef TimeoutObject = js.node.Timers.Timeout; +@:deprecated("Use Timeout instead") typedef IntervalObject = js.node.Timers.Timeout; +@:deprecated("Use Immediate instead") typedef ImmediateObject = js.node.Timers.Immediate; diff --git a/src/js/node/Assert.hx b/src/js/node/Assert.hx index 48df60f2..e9daebf8 100644 --- a/src/js/node/Assert.hx +++ b/src/js/node/Assert.hx @@ -22,15 +22,11 @@ package js.node; -#if haxe4 +import haxe.Constraints.Function; import js.lib.Error; import js.lib.Promise; import js.lib.RegExp; -#else -import js.Error; -import js.Promise; -import js.RegExp; -#end +import js.node.assert.AssertMethods; /** The `assert module` provides a set of assertion functions for verifying invariants. @@ -46,7 +42,7 @@ extern class Assert { @see https://nodejs.org/api/assert.html#assert_strict_mode **/ - static var strict(default, never):Assert; + static var strict(default, never):AssertMethods; /** An alias of `Assert.ok()`. @@ -54,15 +50,15 @@ extern class Assert { @see https://nodejs.org/api/assert.html#assert_assert_value_message **/ @:selfCall - @:overload(function(value:Dynamic, ?message:Error):Void {}) - static function assert(value:Dynamic, ?message:String):Void; + @:overload(function(value:Any, ?message:Error):Void {}) + static function assert(value:Any, ?message:String):Void; /** An alias of `Assert.deepStrictEqual()`. @see https://nodejs.org/api/assert.html#assert_assert_deepequal_actual_expected_message **/ - @:deprecated + @:deprecated("Use deepStrictEqual instead") @:overload(function(actual:T, expected:T, ?message:Error):Void {}) static function deepEqual(actual:T, expected:T, ?message:String):Void; @@ -76,6 +72,14 @@ extern class Assert { @:overload(function(actual:T, expected:T, ?message:Error):Void {}) static function deepStrictEqual(actual:T, expected:T, ?message:String):Void; + /** + Expects the `string` input not to match the regular expression. + + @see https://nodejs.org/api/assert.html#assert_assert_doesnotmatch_string_regexp_message + **/ + @:overload(function(string:String, regexp:RegExp, ?message:Error):Void {}) + static function doesNotMatch(string:String, regexp:RegExp, ?message:String):Void; + /** Awaits the `asyncFn` promise or, if `asyncFn` is a function, immediately calls the function and awaits the returned promise to complete. @@ -83,12 +87,12 @@ extern class Assert { @see https://nodejs.org/api/assert.html#assert_assert_doesnotreject_asyncfn_error_message **/ - @:overload(function(asyncFn:Void->Promise, ?error:Class, ?message:String):Void {}) - @:overload(function(asyncFn:Void->Promise, ?error:RegExp, ?message:String):Void {}) - @:overload(function(asyncFn:Void->Promise, ?error:Dynamic->Bool, ?message:String):Void {}) - @:overload(function(asyncFn:Promise, ?error:Class, ?message:String):Void {}) - @:overload(function(asyncFn:Promise, ?error:RegExp, ?message:String):Void {}) - static function doesNotReject(asyncFn:Promise, ?error:Dynamic->Bool, ?message:String):Void; + @:overload(function(asyncFn:Void->Promise, ?error:Class, ?message:String):Void {}) + @:overload(function(asyncFn:Void->Promise, ?error:RegExp, ?message:String):Void {}) + @:overload(function(asyncFn:Void->Promise, ?error:Any->Bool, ?message:String):Void {}) + @:overload(function(asyncFn:Promise, ?error:Class, ?message:String):Void {}) + @:overload(function(asyncFn:Promise, ?error:RegExp, ?message:String):Void {}) + static function doesNotReject(asyncFn:Promise, ?error:Any->Bool, ?message:String):Void; /** Asserts that the function `fn` does not throw an error. @@ -100,9 +104,9 @@ extern class Assert { @see https://nodejs.org/api/assert.html#assert_assert_doesnotthrow_fn_error_message **/ - @:overload(function(fn:Void->Void, ?error:Class, ?message:String):Void {}) + @:overload(function(fn:Void->Void, ?error:Class, ?message:String):Void {}) @:overload(function(fn:Void->Void, ?error:RegExp, ?message:String):Void {}) - static function doesNotThrow(fn:Void->Void, ?error:Dynamic->Bool, ?message:String):Void; + static function doesNotThrow(fn:Void->Void, ?error:Any->Bool, ?message:String):Void; /** An alias of `strictEqual`. @@ -128,10 +132,10 @@ extern class Assert { @see https://nodejs.org/api/assert.html#assert_assert_fail_actual_expected_message_operator_stackstartfn **/ - @:deprecated + @:deprecated("Use fail with a message or Error instead") @:native("fail") - @:overload(function(actual:T, expected:T, ?message:String, ?operator_:String, ?stackStartFn:haxe.Constraints.Function):Void {}) - static function fail_(actual:T, expected:T, ?message:Error, ?operator_:String, ?stackStartFn:haxe.Constraints.Function):Void; + @:overload(function(actual:T, expected:T, ?message:String, ?operator_:String, ?stackStartFn:Function):Void {}) + static function fail_(actual:T, expected:T, ?message:Error, ?operator_:String, ?stackStartFn:Function):Void; /** Throws `value` if `value` is not `undefined` or `null`. @@ -140,14 +144,22 @@ extern class Assert { @see https://nodejs.org/api/assert.html#assert_assert_iferror_value **/ - static function ifError(value:Dynamic):Void; + static function ifError(value:Any):Void; + + /** + Expects the `string` input to match the regular expression. + + @see https://nodejs.org/api/assert.html#assert_assert_match_string_regexp_message + **/ + @:overload(function(string:String, regexp:RegExp, ?message:Error):Void {}) + static function match(string:String, regexp:RegExp, ?message:String):Void; /** An alias of `Assert.notDeepStrictEqual()`. @see https://nodejs.org/api/assert.html#assert_assert_notdeepequal_actual_expected_message **/ - @:deprecated + @:deprecated("Use notDeepStrictEqual instead") @:overload(function(actual:T, expected:T, ?message:Error):Void {}) static function notDeepEqual(actual:T, expected:T, ?message:String):Void; @@ -164,7 +176,7 @@ extern class Assert { @see https://nodejs.org/api/assert.html#assert_assert_notequal_actual_expected_message **/ - @:deprecated + @:deprecated("Use notStrictEqual instead") @:overload(function(actual:T, expected:T, ?message:Error):Void {}) static function notEqual(actual:T, expected:T, ?message:String):Void; @@ -182,8 +194,18 @@ extern class Assert { @see https://nodejs.org/api/assert.html#assert_assert_ok_value_message **/ - @:overload(function(value:Dynamic, ?message:Error):Void {}) - static function ok(value:Dynamic, ?message:String):Void; + @:overload(function(value:Any, ?message:Error):Void {}) + static function ok(value:Any, ?message:String):Void; + + /** + Tests for partial deep equality between the `actual` and `expected` parameters. + "Partial" equality means that only properties that exist on the `expected` + parameter are compared. + + @see https://nodejs.org/api/assert.html#assert_assert_partialdeepstrictequal_actual_expected_message + **/ + @:overload(function(actual:T, expected:T, ?message:Error):Void {}) + static function partialDeepStrictEqual(actual:T, expected:T, ?message:String):Void; /** Awaits the `asyncFn` promise or, if `asyncFn` is a function, @@ -192,16 +214,16 @@ extern class Assert { @see https://nodejs.org/api/assert.html#assert_assert_rejects_asyncfn_error_message **/ - @:overload(function(asyncFn:Void->Promise, ?error:Class, ?message:String):Void {}) - @:overload(function(asyncFn:Void->Promise, ?error:RegExp, ?message:String):Void {}) - @:overload(function(asyncFn:Void->Promise, ?error:Dynamic->Bool, ?message:String):Void {}) - @:overload(function(asyncFn:Void->Promise, ?error:Dynamic, ?message:String):Void {}) - @:overload(function(asyncFn:Void->Promise, ?error:Error, ?message:String):Void {}) - @:overload(function(asyncFn:Promise, ?error:Class, ?message:String):Void {}) - @:overload(function(asyncFn:Promise, ?error:RegExp, ?message:String):Void {}) - @:overload(function(asyncFn:Promise, ?error:Dynamic->Bool, ?message:String):Void {}) - @:overload(function(asyncFn:Promise, ?error:Dynamic, ?message:String):Void {}) - static function rejects(asyncFn:Promise, ?error:Error, ?message:String):Void; + @:overload(function(asyncFn:Void->Promise, ?error:Class, ?message:String):Void {}) + @:overload(function(asyncFn:Void->Promise, ?error:RegExp, ?message:String):Void {}) + @:overload(function(asyncFn:Void->Promise, ?error:Any->Bool, ?message:String):Void {}) + @:overload(function(asyncFn:Void->Promise, ?error:Any, ?message:String):Void {}) + @:overload(function(asyncFn:Void->Promise, ?error:Error, ?message:String):Void {}) + @:overload(function(asyncFn:Promise, ?error:Class, ?message:String):Void {}) + @:overload(function(asyncFn:Promise, ?error:RegExp, ?message:String):Void {}) + @:overload(function(asyncFn:Promise, ?error:Any->Bool, ?message:String):Void {}) + @:overload(function(asyncFn:Promise, ?error:Any, ?message:String):Void {}) + static function rejects(asyncFn:Promise, ?error:Error, ?message:String):Void; /** Tests strict equality between the `actual` and `expected` parameter as @@ -218,7 +240,7 @@ extern class Assert { @see https://nodejs.org/api/assert.html#assert_assert_throws_fn_error_message **/ @:overload(function(fn:Void->Void, ?error:RegExp, ?message:String):Void {}) - @:overload(function(fn:Void->Void, ?error:Dynamic->Bool, ?message:String):Void {}) - @:overload(function(fn:Void->Void, ?error:Dynamic, ?message:String):Void {}) + @:overload(function(fn:Void->Void, ?error:Any->Bool, ?message:String):Void {}) + @:overload(function(fn:Void->Void, ?error:Any, ?message:String):Void {}) static function throws(fn:Void->Void, ?error:Error, ?message:String):Void; } diff --git a/src/js/node/AsyncHooks.hx b/src/js/node/AsyncHooks.hx new file mode 100644 index 00000000..5e3c4379 --- /dev/null +++ b/src/js/node/AsyncHooks.hx @@ -0,0 +1,87 @@ +/* + * Copyright (C)2014-2020 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package js.node; + +/** + The `async_hooks` module provides an API to track asynchronous resources. + + Prefer `js.node.async_hooks.AsyncLocalStorage` for most application-level async context tracking. + `createHook` remains available but is a lower-level / less recommended API. + + @see https://nodejs.org/docs/latest-v24.x/api/async_hooks.html +**/ +@:jsRequire("async_hooks") +extern class AsyncHooks { + /** + Registers functions to be called for different lifetime events of each async operation. + **/ + static function createHook(options:AsyncHookOptions):js.node.async_hooks.AsyncHook; + + /** + Returns the `asyncId` of the current execution context. + **/ + static function executionAsyncId():Float; + + /** + Returns the resource object associated with the topmost async frame. + Using undocumented handle APIs on the returned object may crash the process. + **/ + // TODO(section-5): type executionAsyncResource beyond Dynamic when handle shapes are modeled + static function executionAsyncResource():Dynamic; + + /** + Returns the `asyncId` of the resource that caused (or "triggered") the current execution. + **/ + static function triggerAsyncId():Float; +} + +/** + Callbacks for `AsyncHooks.createHook`. +**/ +typedef AsyncHookOptions = { + /** + Called during object construction when the resource is initialized. + // TODO(section-5): type resource beyond Dynamic + **/ + @:optional var init:Float->String->Float->Dynamic->Void; + + /** + Called just before the resource's callback is called. + **/ + @:optional var before:Float->Void; + + /** + Called immediately after the resource's callback has completed. + **/ + @:optional var after:Float->Void; + + /** + Called after the resource is destroyed. + **/ + @:optional var destroy:Float->Void; + + /** + Called when the Promise-related callback is resolved. + **/ + @:optional var promiseResolve:Float->Void; +} diff --git a/src/js/node/ChildProcess.hx b/src/js/node/ChildProcess.hx index d21d1a9f..7d90eec9 100644 --- a/src/js/node/ChildProcess.hx +++ b/src/js/node/ChildProcess.hx @@ -24,24 +24,35 @@ package js.node; import haxe.DynamicAccess; import haxe.extern.EitherType; -import js.node.child_process.ChildProcess as ChildProcessObject; -#if haxe4 import js.lib.Error; -#else -import js.Error; -#end +import js.node.child_process.ChildProcess as ChildProcessObject; +import js.node.web.AbortSignal; +import js.node.url.URL; + +/** + Serialization mode for IPC messages between processes. + + @see https://nodejs.org/docs/latest-v24.x/api/child_process.html#advanced-serialization +**/ +enum abstract ChildProcessSerialization(String) from String to String { + var Json = "json"; + var Advanced = "advanced"; +} /** Common options for all `ChildProcess` methods. + + @see https://nodejs.org/docs/latest-v24.x/api/child_process.html **/ private typedef ChildProcessCommonOptions = { /** Current working directory of the child process. + Accepts a path string or WHATWG `URL` object with `file:` protocol. **/ - @:optional var cwd:String; + @:optional var cwd:EitherType; /** - Environment key-value pairs + Environment key-value pairs. **/ @:optional var env:DynamicAccess; @@ -57,12 +68,40 @@ private typedef ChildProcessCommonOptions = { /** Shell to execute the command with. - Default: '/bin/sh' on UNIX, 'cmd.exe' on Windows. + Default: `'/bin/sh'` on UNIX, `'cmd.exe'` on Windows. - The shell should understand the -c switch on UNIX or /s /c on Windows. - On Windows, command line parsing should be compatible with cmd.exe. + The shell should understand the `-c` switch on UNIX or `/s /c` on Windows. + On Windows, command line parsing should be compatible with `cmd.exe`. **/ @:optional var shell:EitherType; + + /** + Hide the subprocess console window that would normally be created on Windows. + Default: `false`. + **/ + @:optional var windowsHide:Bool; + + /** + No quoting or escaping of arguments is done on Windows. + Ignored on Unix. Default: `false`. + **/ + @:optional var windowsVerbatimArguments:Bool; + + /** + Allows aborting the child process using an `AbortSignal`. + **/ + @:optional var signal:AbortSignal; + + /** + Maximum amount of time in milliseconds the process is allowed to run. + **/ + @:optional var timeout:Int; + + /** + The signal value to be used when the spawned process will be killed + by timeout or abort signal. Default: `'SIGTERM'`. + **/ + @:optional var killSignal:EitherType; } /** @@ -75,6 +114,12 @@ private typedef ChildProcessSpawnOptionsBase = { Child's stdio configuration. **/ @:optional var stdio:ChildProcessSpawnOptionsStdio; + + /** + Specify the kind of serialization used for sending messages between processes. + Possible values are `'json'` and `'advanced'`. Default: `'json'`. + **/ + @:optional var serialization:ChildProcessSerialization; } /** @@ -84,9 +129,15 @@ typedef ChildProcessSpawnOptions = { > ChildProcessSpawnOptionsBase, /** - The child will be a process group leader. + The child will be a process group leader / can keep running after parent exits. **/ @:optional var detached:Bool; + + /** + Explicitly set the value of `argv[0]` sent to the child process. + This will be set to `command` if not specified. + **/ + @:optional var argv0:String; } /** @@ -104,29 +155,14 @@ typedef ChildProcessSpawnSyncOptions = { The value is one of the following: * 'pipe' - Create a pipe between the child process and the parent process. - The parent end of the pipe is exposed to the parent as a property on the child_process object as ChildProcess.stdio[fd]. - Pipes created for fds 0 - 2 are also available as ChildProcess.stdin, ChildProcess.stdout and ChildProcess.stderr, respectively. - - * 'ipc' - Create an IPC channel for passing messages/file descriptors between parent and child. - A ChildProcess may have at most one IPC stdio file descriptor. Setting this option enables the ChildProcess.send() method. - If the child writes JSON messages to this file descriptor, then this will trigger ChildProcess.on('message'). - If the child is a Node.js program, then the presence of an IPC channel will enable process.send() and process.on('message'). - - * 'ignore' - Do not set this file descriptor in the child. Note that Node will always open fd 0 - 2 for the processes it spawns. - When any of these is ignored node will open /dev/null and attach it to the child's fd. - - * Stream object - Share a readable or writable stream that refers to a tty, file, socket, or a pipe with the child process. - The stream's underlying file descriptor is duplicated in the child process to the fd that corresponds to the index - in the stdio array. Note that the stream must have an underlying descriptor (file streams do not until the 'open' - event has occurred). - - * Positive integer - The integer value is interpreted as a file descriptor that is is currently open in the parent process. - It is shared with the child process, similar to how Stream objects can be shared. - - * null - Use default value. For stdio fds 0, 1 and 2 (in other words, stdin, stdout, and stderr) a pipe is created. - For fd 3 and up, the default is 'ignore'. - - As a shorthand, the stdio argument may also be one of the following strings, rather than an array: + * 'ipc' - Create an IPC channel for passing messages/file descriptors. + * 'ignore' - Do not set this file descriptor in the child. + * 'inherit' - Pass through the corresponding stdio stream to/from the parent. + * Stream object - Share a readable or writable stream with the child process. + * Positive integer - A file descriptor that is currently open in the parent. + * null / undefined - Use default value. + + As a shorthand, the stdio argument may also be one of the following strings: ignore - ['ignore', 'ignore', 'ignore'] pipe - ['pipe', 'pipe', 'pipe'] inherit - [process.stdin, process.stdout, process.stderr] or [0,1,2] @@ -138,19 +174,24 @@ typedef ChildProcessSpawnOptionsStdio = EitherType>>; +// Ideal type: Array>> +// TODO(section-5): replace Array once nested EitherType arrays type-check reliably typedef ChildProcessSpawnOptionsStdioFull = Array; /** @@ -197,24 +236,14 @@ private typedef ChildProcessExecOptionsBase = { > ChildProcessCommonOptions, /** - Default: 'utf8' + Default: `'utf8'` **/ @:optional var encoding:String; - /** - If greater than 0, then it will kill the child process if it runs longer than timeout milliseconds. - **/ - @:optional var timeout:Int; - - /** - The child process is killed with `killSignal` (default: 'SIGTERM'). - **/ - @:optional var killSignal:String; - /** The largest amount of data allowed on stdout or stderr. If this value is exceeded then the child process is killed. - Default: 200*1024 + Default: `1024 * 1024` **/ @:optional var maxBuffer:Int; } @@ -240,21 +269,31 @@ typedef ChildProcessForkOptions = { > ChildProcessCommonOptions, /** - Executable used to create the child process + Executable used to create the child process. **/ @:optional var execPath:String; /** - List of string arguments passed to the executable (Default: process.execArgv) + List of string arguments passed to the executable (Default: `process.execArgv`) **/ @:optional var execArgv:Array; /** If `true`, stdin, stdout, and stderr of the child will be piped to the parent, - otherwise they will be inherited from the parent, see the "pipe" and "inherit" - options for `ChildProcessSpawnOptions.stdio` for more details (default is `false`) + otherwise they will be inherited from the parent (default is `false`). **/ @:optional var silent:Bool; + + /** + See `ChildProcessSpawnOptions.stdio`. When provided, overrides `silent`. + Must contain exactly one `'ipc'` entry when using the array form. + **/ + @:optional var stdio:ChildProcessSpawnOptionsStdio; + + /** + Specify the kind of serialization used for sending messages between processes. + **/ + @:optional var serialization:ChildProcessSerialization; } /** @@ -263,7 +302,7 @@ typedef ChildProcessForkOptions = { @:native("Error") extern class ChildProcessExecError extends Error { /** - the exit code of the child proces. + the exit code of the child process. **/ var code(default, null):Int; @@ -281,8 +320,8 @@ extern class ChildProcessExecError extends Error { and `error.code` will be the exit code of the child process, and `error.signal` will be set to the signal that terminated the process (see `ChildProcessExecError`). **/ -typedef ChildProcessExecCallback = #if (haxe_ver >= 4) (error:Null, stdout:EitherType, - stderr:EitherType) -> Void; #else Null->EitherType->EitherType->Void; #end +typedef ChildProcessExecCallback = (error:Null, stdout:EitherType, + stderr:EitherType) -> Void; /** Object returned from the `spawnSync` method. @@ -296,7 +335,7 @@ typedef ChildProcessSpawnSyncResult = { /** Array of results from stdio output **/ - var output:Array>; + var output:Array>>; /** The contents of output[1] @@ -311,12 +350,12 @@ typedef ChildProcessSpawnSyncResult = { /** The exit code of the child process **/ - var status:Int; + var status:Null; /** The signal used to kill the child process **/ - var signal:String; + var signal:Null; /** The error object if the child process failed or timed out @@ -324,19 +363,16 @@ typedef ChildProcessSpawnSyncResult = { var error:Error; } +/** + The `child_process` module enables spawning child processes. + + @see https://nodejs.org/docs/latest-v24.x/api/child_process.html +**/ @:jsRequire("child_process") extern class ChildProcess { /** Launches a new process with the given `command`, with command line arguments in `args`. If omitted, `args` defaults to an empty `Array`. - - The third argument is used to specify additional options, which defaults to: - { cwd: null, - env: process.env - } - - Note that if spawn receives an empty options object, it will result in spawning the process with an empty - environment rather than using `process.env`. This due to backwards compatibility issues with a deprecated API. **/ @:overload(function(command:String, ?options:ChildProcessSpawnOptions):ChildProcessObject {}) @:overload(function(command:String, args:Array, ?options:ChildProcessSpawnOptions):ChildProcessObject {}) @@ -344,23 +380,12 @@ extern class ChildProcess { /** Runs a command in a shell and buffers the output. - - `command` is the command to run, with space-separated arguments. - - The default `options` are: - { encoding: 'utf8', - timeout: 0, - maxBuffer: 200*1024, - killSignal: 'SIGTERM', - cwd: null, - env: null } **/ @:overload(function(command:String, options:ChildProcessExecOptions, callback:ChildProcessExecCallback):ChildProcessObject {}) static function exec(command:String, callback:ChildProcessExecCallback):ChildProcessObject; /** - This is similar to `exec` except it does not execute a subshell but rather the specified file directly. - This makes it slightly leaner than `exec` + Similar to `exec` except it does not execute a subshell but rather the specified file directly. **/ @:overload(function(file:String, args:Array, options:ChildProcessExecFileOptions, ?callback:ChildProcessExecCallback):ChildProcessObject {}) @:overload(function(file:String, options:ChildProcessExecFileOptions, ?callback:ChildProcessExecCallback):ChildProcessObject {}) @@ -368,36 +393,21 @@ extern class ChildProcess { static function execFile(file:String, ?callback:ChildProcessExecCallback):ChildProcessObject; /** - This is a special case of the `spawn` functionality for spawning Node processes. - In addition to having all the methods in a normal `ChildProcess` instance, - the returned object has a communication channel built-in. - See `send` for details. + Special case of `spawn` for spawning Node.js processes with an IPC channel. **/ - @:overload(function(modulePath:String, args:Array, options:ChildProcessForkOptions):ChildProcessObject {}) - @:overload(function(modulePath:String, options:ChildProcessForkOptions):ChildProcessObject {}) - static function fork(modulePath:String, ?args:Array):ChildProcessObject; + @:overload(function(modulePath:EitherType, args:Array, options:ChildProcessForkOptions):ChildProcessObject {}) + @:overload(function(modulePath:EitherType, options:ChildProcessForkOptions):ChildProcessObject {}) + static function fork(modulePath:EitherType, ?args:Array):ChildProcessObject; /** Synchronous version of `spawn`. - - `spawnSync` will not return until the child process has fully closed. - When a timeout has been encountered and `killSignal` is sent, the method won't return until the process - has completely exited. That is to say, if the process handles the SIGTERM signal and doesn't exit, - your process will wait until the child process has exited. **/ @:overload(function(command:String, args:Array, ?options:ChildProcessSpawnSyncOptions):ChildProcessSpawnSyncResult {}) static function spawnSync(command:String, ?options:ChildProcessSpawnSyncOptions):ChildProcessSpawnSyncResult; /** Synchronous version of `execFile`. - - `execFileSync` will not return until the child process has fully closed. - When a timeout has been encountered and `killSignal` is sent, the method won't return until the process - has completely exited. That is to say, if the process handles the SIGTERM signal and doesn't exit, - your process will wait until the child process has exited. - If the process times out, or has a non-zero exit code, this method will throw. - The Error object will contain the entire result from `spawnSync` **/ @:overload(function(command:String, ?options:ChildProcessSpawnSyncOptions):EitherType {}) @:overload(function(command:String, args:Array, ?options:ChildProcessSpawnSyncOptions):EitherType {}) @@ -405,14 +415,7 @@ extern class ChildProcess { /** Synchronous version of `exec`. - - `execSync` will not return until the child process has fully closed. - When a timeout has been encountered and `killSignal` is sent, the method won't return until the process - has completely exited. That is to say, if the process handles the SIGTERM signal and doesn't exit, - your process will wait until the child process has exited. - If the process times out, or has a non-zero exit code, this method will throw. - The Error object will contain the entire result from `spawnSync` **/ static function execSync(command:String, ?options:ChildProcessSpawnSyncOptions):EitherType; } diff --git a/src/js/node/Cluster.hx b/src/js/node/Cluster.hx index 3673863d..6aaa9232 100644 --- a/src/js/node/Cluster.hx +++ b/src/js/node/Cluster.hx @@ -23,76 +23,54 @@ package js.node; import haxe.DynamicAccess; +import js.node.ChildProcess.ChildProcessSerialization; +import js.node.ChildProcess.ChildProcessSpawnOptionsStdio; import js.node.cluster.Worker; import js.node.events.EventEmitter; +/** + @see https://nodejs.org/docs/latest-v24.x/api/cluster.html +**/ enum abstract ClusterEvent(Event) to Event { /** When a new worker is forked the cluster module will emit a 'fork' event. This can be used to log worker activity, and create your own timeout. - - Listener arguments: - * worker:Worker **/ var Fork:ClusterEventVoid> = "fork"; /** After forking a new worker, the worker should respond with an online message. - When the master receives an online message it will emit this event. - - The difference between 'fork' and 'online' is that fork is emitted when the master forks a worker, - and 'online' is emitted when the worker is running. - - Listener arguments: - * worker:Worker + When the primary receives an online message it will emit this event. **/ var Online:ClusterEventVoid> = "online"; /** After calling `listen` from a worker, when the 'listening' event is emitted on the server, - a listening event will also be emitted on cluster in the master. - - The event handler is executed with two arguments, the `worker` contains the worker object and - the `address` object contains the following connection properties: address, port and addressType. - This is very useful if the worker is listening on more than one address. - - Listener arguments: - * worker:Worker - * address:ListeningEventAddress + a listening event will also be emitted on cluster in the primary. **/ var Listening:ClusterEventListeningEventAddress->Void> = "listening"; /** Emitted after the worker IPC channel has disconnected. - - This can occur when a worker exits gracefully, is killed, - or is disconnected manually (such as with `Worker.disconnect`). - - There may be a delay between the 'disconnect' and 'exit' events. - - These events can be used to detect if the process is stuck in a cleanup - or if there are long-living connections. - - Listener arguments: - * worker:Worker **/ var Disconnect:ClusterEventVoid> = "disconnect"; /** When any of the workers die the cluster module will emit the 'exit' event. - This can be used to restart the worker by calling `Cluster.fork` again. - - Listener arguments: - * worker:Worker - * code:Int - the exit code, if it exited normally. - * signal:String - the name of the signal (eg. 'SIGHUP') that caused the process to be killed. **/ var Exit:ClusterEventInt->String->Void> = "exit"; /** - Emitted the first time that `Cluster.setupMaster` is called. + Emitted every time `setupPrimary` is called. **/ var Setup:ClusterEventVoid> = "setup"; + + /** + Emitted when any worker receives a message. + + // TODO(section-5): tighten message/handle typing beyond Dynamic + **/ + var Message:ClusterEventDynamic->Dynamic->Void> = "message"; } /** @@ -119,13 +97,9 @@ extern enum abstract ClusterSchedulingPolicy(Int) { } /** - A single instance of Node runs in a single thread. - To take advantage of multi-core systems the user will sometimes want to launch a cluster of Node processes to handle the load. - The cluster module allows you to easily create child processes that all share server ports. + The cluster module allows easy creation of child processes that all share server ports. - This feature was introduced recently, and may change in future versions. Please try it out and provide feedback. - - Also note that, on Windows, it is not yet possible to set up a named pipe server in a worker. + @see https://nodejs.org/docs/latest-v24.x/api/cluster.html **/ @:jsRequire("cluster") extern class Cluster extends EventEmitter { @@ -139,92 +113,63 @@ extern class Cluster extends EventEmitter { /** The scheduling policy, either `SCHED_RR` for round-robin or `SCHED_NONE` to leave it to the operating system. - - This is a global setting and effectively frozen once you spawn the first worker - or call `setupMaster`, whatever comes first. - - `SCHED_RR` is the default on all operating systems except Windows. - Windows will change to `SCHED_RR` once libuv is able to effectively distribute IOCP handles - without incurring a large performance hit. - - `schedulingPolicy` can also be set through the NODE_CLUSTER_SCHED_POLICY environment variable. - Valid values are "rr" and "none". **/ var schedulingPolicy:ClusterSchedulingPolicy; /** - After calling `setupMaster` (or `fork`) this settings object will contain the settings, including the default values. - - It is effectively frozen after being set, because `setupMaster` can only be called once. - - This object is not supposed to be changed or set manually, by you. + After calling `setupPrimary` (or `fork`) this settings object will contain the settings, + including the default values. **/ var settings(default, null):ClusterSettings; /** - True if the process is a master. - This is determined by the process.env.NODE_UNIQUE_ID. - If process.env.NODE_UNIQUE_ID is undefined, then `isMaster` is true. + True if the process is a primary. + Deprecated alias for `isPrimary`. **/ + @:deprecated("Use isPrimary instead") var isMaster(default, null):Bool; /** - True if the process is not a master (it is the negation of `isMaster`). + True if the process is a primary. + This is determined by the process.env.NODE_UNIQUE_ID. + If process.env.NODE_UNIQUE_ID is undefined, then `isPrimary` is true. **/ - var isWorker(default, null):Bool; + var isPrimary(default, null):Bool; /** - `setupMaster` is used to change the default `fork` behavior. - - Once called, the `settings` will be present in `settings`. - - Note that: - Only the first call to `setupMaster` has any effect, subsequent calls are ignored - - That because of the above, the only attribute of a worker that may be customized per-worker - is the `env` passed to `fork` + True if the process is not a primary (it is the negation of `isPrimary`). + **/ + var isWorker(default, null):Bool; - `fork` calls `setupMaster` internally to establish the defaults, so to have any effect, - `setupMaster` must be called before any calls to `fork` + /** + Deprecated alias for `setupPrimary`. **/ - function setupMaster(?settings:{?exec:String, ?args:Array, ?silent:Bool}):Void; + @:deprecated("Use setupPrimary instead") + function setupMaster(?settings:ClusterSettings):Void; /** - Spawn a new worker process. + Used to change the default `fork` behavior. Once called, the settings will be present in `settings`. + **/ + function setupPrimary(?settings:ClusterSettings):Void; - This can only be called from the master process. + /** + Spawn a new worker process. This can only be called from the primary process. **/ function fork(?env:DynamicAccess):Worker; /** Calls `disconnect` on each worker in `workers`. - - When they are disconnected all internal handles will be closed, - allowing the master process to die gracefully if no other event is waiting. - - The method takes an optional `callback` argument which will be called when finished. - - This can only be called from the master process. **/ function disconnect(?callback:Void->Void):Void; /** - A reference to the current worker object. - - Not available in the master process. + A reference to the current worker object. Not available in the primary process. **/ var worker(default, null):Worker; /** A hash that stores the active worker objects, keyed by `id` field. - Makes it easy to loop through all the workers. - - It is only available in the master process. - - A worker is removed from `workers` just before the 'disconnect' or 'exit' event is emitted. - - Should you wish to reference a worker over a communication channel, using the worker's unique `id` - is the easiest way to find the worker. + It is only available in the primary process. **/ var workers(default, null):DynamicAccess; } @@ -234,33 +179,62 @@ typedef ClusterSettings = { list of string arguments passed to the node executable. Default: process.execArgv **/ - @:optional var execArgv(default, null):Array; + @:optional var execArgv:Array; /** file path to worker file. Default: process.argv[1] **/ - @:optional var exec(default, null):String; + @:optional var exec:String; /** string arguments passed to worker. Default: process.argv.slice(2) **/ - @:optional var args(default, null):Array; + @:optional var args:Array; + + /** + Current working directory of the worker process. + Default: `undefined` (inherits from parent process). + **/ + @:optional var cwd:String; + + /** + Specify the kind of serialization used for sending messages between processes. + **/ + @:optional var serialization:ChildProcessSerialization; /** whether or not to send output to parent's stdio. Default: false **/ - @:optional var silent(default, null):Bool; + @:optional var silent:Bool; + + /** + Configures the stdio of forked processes. + Must contain an `'ipc'` entry. When provided, overrides `silent`. + **/ + @:optional var stdio:ChildProcessSpawnOptionsStdio; /** Sets the user identity of the process. **/ - @:optional var uid(default, null):Int; + @:optional var uid:Int; /** Sets the group identity of the process. **/ - @:optional var gid(default, null):Int; + @:optional var gid:Int; + + /** + Sets inspector port of worker. Can be a number, or a function that returns a number. + **/ + // TODO(section-5): model inspectPort callback `() -> Int` without losing Int assignability + @:optional var inspectPort:haxe.extern.EitherTypeInt>; + + /** + Hide the forked processes console window that would normally be created on Windows. + Default: `false`. + **/ + @:optional var windowsHide:Bool; } diff --git a/src/js/node/Constants.hx b/src/js/node/Constants.hx index 790b1ec6..a966f665 100644 --- a/src/js/node/Constants.hx +++ b/src/js/node/Constants.hx @@ -22,6 +22,15 @@ package js.node; +/** + Constants exported by Node.js core modules (legacy aggregate module). + + Prefer module-specific constants (e.g. `fs.constants`, `os.constants`, `crypto.constants`) + over `require('constants')`. This extern only mirrors a subset historically used by + crypto engine/padding callers. + + @see https://nodejs.org/api/crypto.html#crypto-constants +**/ @:jsRequire("constants") extern class Constants { static var ENGINE_METHOD_RSA(default, null):Int; diff --git a/src/js/node/Crypto.hx b/src/js/node/Crypto.hx index 007ee024..40b08c18 100644 --- a/src/js/node/Crypto.hx +++ b/src/js/node/Crypto.hx @@ -22,16 +22,16 @@ package js.node; +import haxe.DynamicAccess; import haxe.extern.EitherType; +import js.html.SubtleCrypto; +import js.lib.ArrayBuffer; +import js.lib.ArrayBufferView; +import js.lib.Error; import js.node.Buffer; import js.node.crypto.*; import js.node.crypto.DiffieHellman.IDiffieHellman; import js.node.tls.SecureContext; -#if haxe4 -import js.lib.Error; -#else -import js.Error; -#end /** Enumerations of crypto algorighms to be used. @@ -83,20 +83,66 @@ extern class Crypto { Note that new programs will probably expect buffers, so only use this as a temporary measure. **/ - @:deprecated + @:deprecated("Use explicitly set encoding on crypto streams instead") static var DEFAULT_ENCODING:String; /** Property for checking and controlling whether a FIPS compliant crypto provider is currently in use. Setting to true requires a FIPS build of Node.js. + + Deprecated since Node.js v10.0.0. Use `getFips` / `setFips` instead. **/ + @:deprecated("Use crypto.setFips() / getFips() instead") static var fips:Bool; + /** + OpenSSL crypto constants (padding modes, DH check codes, engine methods, etc.). + **/ + static var constants(default, never):DynamicAccess; + + /** + A convenient alias for `Crypto.webcrypto.subtle`. + **/ + static var subtle(default, never):SubtleCrypto; + + /** + Node.js Web Crypto API implementation (`crypto.webcrypto`). + + Typed as the Haxe std `js.html.Crypto` surface. Node-specific Web Crypto + extensions beyond that DOM typedef are not duplicated here — no separate + `js.node.webcrypto` package. + + // TODO(section-4): audit Node-only Web Crypto additions vs `js.html.Crypto` + **/ + static var webcrypto(default, never):js.html.Crypto; + + /** + Returns `1` if and only if a FIPS compliant crypto provider is currently in use, `0` otherwise. + **/ + static function getFips():Int; + + /** + Enables the FIPS compliant crypto provider in a FIPS-enabled Node.js build. + Throws an error if FIPS mode is not available. + **/ + static function setFips(bool:Bool):Void; + /** Returns an array with the names of the supported ciphers. **/ static function getCiphers():Array; + /** + Returns information about a given cipher. + + Some ciphers accept variable length keys and initialization vectors. + By default, the method will return the default values for these ciphers. + To test if a given key length or IV length is acceptable for a given cipher, + use the `keyLength` and `ivLength` options. + If the given values are unacceptable, `null`/`undefined` will be returned. + **/ + static function getCipherInfo(nameOrNid:EitherType, ?options:CipherInfoOptions):Null; + /** Returns an array with the names of the supported hash algorithms. **/ @@ -153,6 +199,7 @@ extern class Crypto { `key` and `iv` must be 'binary' encoded strings or buffers. **/ + @:overload(function(algorithm:String, key:EitherType, KeyObject>, iv:Null>):Cipher {}) static function createCipheriv(algorithm:String, key:EitherType, iv:EitherType):Cipher; /** @@ -165,6 +212,7 @@ extern class Crypto { Creates and returns a decipher object, with the given algorithm, key and iv. This is the mirror of the `createCipheriv` above. **/ + @:overload(function(algorithm:String, key:EitherType, KeyObject>, iv:Null>):Decipher {}) static function createDecipheriv(algorithm:String, key:EitherType, iv:EitherType):Decipher; /** @@ -200,6 +248,11 @@ extern class Crypto { **/ static function getDiffieHellman(group_name:DiffieHellmanGroupName):IDiffieHellman; + /** + An alias for `getDiffieHellman`. + **/ + static function createDiffieHellmanGroup(name:DiffieHellmanGroupName):DiffieHellmanGroup; + /** Creates an Elliptic Curve (EC) Diffie-Hellman key exchange object using a predefined curve specified by the `curve_name` string. Use `getCurves` to obtain a list of available curve names. @@ -208,6 +261,22 @@ extern class Crypto { **/ static function createECDH(curve_name:String):ECDH; + /** + Creates and returns a new key object containing a private key. + **/ + static function createPrivateKey(key:EitherType>):KeyObject; + + /** + Creates and returns a new key object containing a public key. + **/ + static function createPublicKey(key:EitherType>>):KeyObject; + + /** + Creates and returns a new key object containing a secret key for symmetric encryption or `Hmac`. + **/ + @:overload(function(key:String, encoding:String):KeyObject {}) + static function createSecretKey(key:EitherType>):KeyObject; + /** Asynchronous PBKDF2 applies pseudorandom function HMAC-SHA1 to derive a key of given length from the given password, salt and iterations. @@ -222,6 +291,37 @@ extern class Crypto { **/ static function pbkdf2Sync(password:EitherType, salt:EitherType, iterations:Int, keylen:Int, ?digest:String):Buffer; + /** + Provides an asynchronous scrypt implementation. + Scrypt is a password-based key derivation function that is designed to be expensive + computationally and memory-wise in order to make brute-force attacks unrewarding. + **/ + @:overload(function(password:EitherType, salt:EitherType, keylen:Int, options:ScryptOptions, + callback:Error->Buffer->Void):Void {}) + static function scrypt(password:EitherType, salt:EitherType, keylen:Int, callback:Error->Buffer->Void):Void; + + /** + Provides a synchronous scrypt implementation. + **/ + static function scryptSync(password:EitherType, salt:EitherType, keylen:Int, ?options:ScryptOptions):Buffer; + + /** + HKDF is a simple key derivation function defined in RFC 5869. + The given `ikm`, `salt` and `info` are used with the `digest` to derive a key of `keylen` bytes. + + The successfully generated derived key is passed to the callback as an `ArrayBuffer`. + **/ + static function hkdf(digest:String, ikm:EitherType, salt:EitherType, info:EitherType, keylen:Int, + callback:Error->ArrayBuffer->Void):Void; + + /** + Provides a synchronous HKDF key derivation function as defined in RFC 5869. + + Returns the derived key as an `ArrayBuffer`. + **/ + static function hkdfSync(digest:String, ikm:EitherType, salt:EitherType, info:EitherType, + keylen:Int):ArrayBuffer; + /** Generates cryptographically strong pseudo-random data. @@ -235,6 +335,69 @@ extern class Crypto { @:overload(function(size:Int, callback:Error->Buffer->Void):Void {}) static function randomBytes(size:Int):Buffer; + /** + This function is similar to `randomBytes` but requires the first argument to be a `Buffer` or `TypedArray` + that will be filled. It also requires that a callback is passed in. + + The supplied callback is invoked with two arguments: `err` and `buf`. + The `buf` argument is a reference to the `buffer` filled with random data. + **/ + @:overload(function(buffer:T, offset:Int, callback:Error->T->Void):Void {}) + @:overload(function(buffer:T, offset:Int, size:Int, callback:Error->T->Void):Void {}) + static function randomFill(buffer:T, callback:Error->T->Void):Void; + + /** + Synchronous version of `randomFill`. Returns the filled buffer. + **/ + @:overload(function(buffer:T, offset:Int):T {}) + @:overload(function(buffer:T, offset:Int, size:Int):T {}) + static function randomFillSync(buffer:T):T; + + /** + Return a random integer `n` such that `min <= n < max`. + This implementation avoids modulo bias. + + The range (`max - min`) must be less than 2^48. `min` and `max` must be safe integers. + + If the callback function is not provided, the random integer is generated synchronously. + **/ + @:overload(function(max:Int, callback:Error->Int->Void):Void {}) + @:overload(function(min:Int, max:Int):Int {}) + @:overload(function(min:Int, max:Int, callback:Error->Int->Void):Void {}) + static function randomInt(max:Int):Int; + + /** + Generates a random RFC 4122 version 4 UUID. + The UUID is generated using a cryptographic pseudorandom number generator. + **/ + static function randomUUID(?options:RandomUUIDOptions):String; + + /** + Generates a random RFC 9562 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. + Added in Node.js v24.16.0 (Active LTS). + **/ + static function randomUUIDv7(?options:RandomUUIDOptions):String; + + /** + Compares the underlying bytes that represent the given `ArrayBuffer`, `Buffer`, + or `ArrayBufferView` instances using a constant-time algorithm. + `a` and `b` must have the same byte length. + **/ + static function timingSafeEqual(a:CryptoArrayBufferLike, b:CryptoArrayBufferLike):Bool; + + /** + Checks the primality of the `candidate`. + **/ + @:overload(function(candidate:CryptoArrayBufferLike, options:CheckPrimeOptions, callback:Error->Bool->Void):Void {}) + static function checkPrime(candidate:CryptoArrayBufferLike, callback:Error->Bool->Void):Void; + + /** + Checks the primality of the `candidate` (synchronous version). + **/ + static function checkPrimeSync(candidate:CryptoArrayBufferLike, ?options:CheckPrimeOptions):Bool; + /** Decrypts `buffer` with `private_key`. @@ -280,6 +443,111 @@ extern class Crypto { **/ @:overload(function(public_key:CryptoKeyOptions, buffer:Buffer):Buffer {}) static function publicEncrypt(public_key:String, buffer:Buffer):Buffer; + + /** + Asynchronously generates a new random secret key of the given `length`. + `type` is currently `'hmac'` or `'aes'`. + **/ + static function generateKey(type:String, options:GenerateKeyOptions, callback:Error->KeyObject->Void):Void; + + /** + Synchronously generates a new random secret key of the given `length`. + `type` is currently `'hmac'` or `'aes'`. + **/ + static function generateKeySync(type:String, options:GenerateKeyOptions):KeyObject; + + /** + Generates a new asymmetric key pair of the given `type`. + + // TODO(section-4): finer-grained overloads per key type / encoding (RSA, EC, Ed25519, …) + **/ + @:overload(function(type:String, options:Any, callback:Error->EitherType->EitherType->Void):Void {}) + @:overload(function(type:String, callback:Error->KeyObject->KeyObject->Void):Void {}) + static function generateKeyPair(type:String, options:Any, callback:Error->KeyObject->KeyObject->Void):Void; + + /** + Synchronously generates a new asymmetric key pair of the given `type`. + + // TODO(section-4): finer-grained return encodings per key type + **/ + @:overload(function(type:String):KeyPairKeyObjectResult {}) + static function generateKeyPairSync(type:String, ?options:Any):EitherType; + + /** + Generates a pseudorandom prime of `size` bits. + **/ + @:overload(function(size:Int, options:GeneratePrimeOptions, callback:Error->EitherType->Void):Void {}) + static function generatePrime(size:Int, callback:Error->ArrayBuffer->Void):Void; + + /** + Generates a pseudorandom prime of `size` bits (synchronous). + **/ + static function generatePrimeSync(size:Int, ?options:GeneratePrimeOptions):EitherType; + + /** + One-shot hashing. Returns a digest for `data` using `algorithm`. + **/ + @:overload(function(algorithm:String, data:EitherType>, options:HashOptions):EitherType {}) + static function hash(algorithm:String, data:EitherType>, ?encoding:String):EitherType; + + /** + Calculates and returns the signature for `data` using the given private key and algorithm. + **/ + @:overload(function(algorithm:Null, data:EitherType, key:EitherType>, + callback:Error->Buffer->Void):Void {}) + static function sign(algorithm:Null, data:EitherType, + key:EitherType>>):Buffer; + + /** + Verifies the given signature for `data` using the given key and algorithm. + **/ + @:overload(function(algorithm:Null, data:EitherType, + key:EitherType>>, signature:EitherType, + callback:Error->Bool->Void):Void {}) + static function verify(algorithm:Null, data:EitherType, + key:EitherType>>, + signature:EitherType):Bool; + + /** + Computes the Diffie-Hellman shared secret based on a `privateKey` and a `publicKey`. + **/ + @:overload(function(options:DiffieHellmanOptions, callback:Error->Buffer->Void):Void {}) + static function diffieHellman(options:DiffieHellmanOptions):Buffer; + + /** + A Web Crypto-compatible implementation of `getRandomValues`. + **/ + static function getRandomValues(typedArray:T):T; + + /** + Returns information about the secure heap usage used by OpenSSL. + **/ + static function secureHeapUsed():SecureHeapUsage; + + /** + Key encapsulation (KEM) using a public key. + **/ + @:overload(function(key:EitherType>>, + callback:Error->EncapsulateResult->Void):Void {}) + static function encapsulate(key:EitherType>>):EncapsulateResult; + + /** + Key decapsulation using a private key. + **/ + @:overload(function(key:EitherType>>, + ciphertext:EitherType, callback:Error->Buffer->Void):Void {}) + static function decapsulate(key:EitherType>>, + ciphertext:EitherType):Buffer; + + /** + Provides an asynchronous Argon2 implementation. + **/ + static function argon2(algorithm:Argon2Algorithm, parameters:Argon2Parameters, callback:Error->Buffer->Void):Void; + + /** + Provides a synchronous Argon2 implementation. + **/ + static function argon2Sync(algorithm:Argon2Algorithm, parameters:Argon2Parameters):Buffer; } /** @@ -304,3 +572,230 @@ typedef CryptoKeyOptions = { **/ @:optional var padding:Int; } + +/** + Binary input accepted by several crypto helpers (`ArrayBuffer`, `Buffer`, or `ArrayBufferView`). +**/ +typedef CryptoArrayBufferLike = EitherType>; + +/** + Options for `Crypto.scrypt` and `Crypto.scryptSync`. +**/ +typedef ScryptOptions = { + /** + CPU/memory cost parameter. Must be a power of two greater than one. Default: `16384`. + Only one of `cost` or `N` may be specified. + **/ + @:optional var cost:Int; + + /** + Block size parameter. Default: `8`. + Only one of `blockSize` or `r` may be specified. + **/ + @:optional var blockSize:Int; + + /** + Parallelization parameter. Default: `1`. + Only one of `parallelization` or `p` may be specified. + **/ + @:optional var parallelization:Int; + + /** + Alias for `cost`. Only one of `cost` or `N` may be specified. + **/ + @:optional var N:Int; + + /** + Alias for `blockSize`. Only one of `blockSize` or `r` may be specified. + **/ + @:optional var r:Int; + + /** + Alias for `parallelization`. Only one of `parallelization` or `p` may be specified. + **/ + @:optional var p:Int; + + /** + Memory upper bound. It is an error when (approximately) `128 * N * r > maxmem`. + Default: `32 * 1024 * 1024`. + **/ + @:optional var maxmem:Int; +} + +/** + Options for `Crypto.randomUUID`. +**/ +typedef RandomUUIDOptions = { + /** + By default, to improve performance, Node.js generates and caches enough random data + to generate up to 128 random UUIDs. To generate a UUID without using the cache, + set `disableEntropyCache` to `true`. Default: `false`. + **/ + @:optional var disableEntropyCache:Bool; +} + +/** + Options for `Crypto.checkPrime` and `Crypto.checkPrimeSync`. +**/ +typedef CheckPrimeOptions = { + /** + The number of Miller-Rabin probabilistic primality iterations to perform. + When the value is `0`, a number of checks is used that yields a false positive rate + of at most 2^-64 for random input. Default: `0`. + **/ + @:optional var checks:Int; +} + +/** + Options for `Crypto.getCipherInfo`. +**/ +typedef CipherInfoOptions = { + /** + A test key length. + **/ + @:optional var keyLength:Int; + + /** + A test IV length. + **/ + @:optional var ivLength:Int; +} + +/** + Information about a cipher returned by `Crypto.getCipherInfo`. +**/ +typedef CipherInfo = { + /** + The name of the cipher. + **/ + var name:String; + + /** + The nid of the cipher. + **/ + var nid:Int; + + /** + The block size of the cipher in bytes. + This property is omitted when `mode` is `'stream'`. + **/ + @:optional var blockSize:Int; + + /** + The expected or default initialization vector length in bytes. + This property is omitted if the cipher does not use an initialization vector. + **/ + @:optional var ivLength:Int; + + /** + The expected or default key length in bytes. + **/ + @:optional var keyLength:Int; + + /** + The cipher mode. One of `'cbc'`, `'ccm'`, `'cfb'`, `'ctr'`, `'ecb'`, `'gcm'`, + `'ocb'`, `'ofb'`, `'stream'`, `'wrap'`, `'xts'`. + **/ + @:optional var mode:String; +} + +/** + Input object accepted by several crypto key helpers. +**/ +typedef CryptoKeyInput = { + var key:EitherType>; + @:optional var format:String; + @:optional var type:String; + @:optional var passphrase:EitherType; + @:optional var encoding:String; +} + +/** + Options for `Crypto.generateKey` / `generateKeySync`. +**/ +typedef GenerateKeyOptions = { + var length:Int; +} + +/** + Result when `generateKeyPairSync` returns KeyObject instances. +**/ +typedef KeyPairKeyObjectResult = { + var publicKey:KeyObject; + var privateKey:KeyObject; +} + +/** + Result when `generateKeyPairSync` returns encoded keys. +**/ +typedef KeyPairEncodedResult = { + var publicKey:EitherType; + var privateKey:EitherType; +} + +/** + Options for `Crypto.generatePrime` / `generatePrimeSync`. +**/ +typedef GeneratePrimeOptions = { + @:optional var safe:Bool; + @:optional var bigint:Bool; + @:optional var add:EitherType; + @:optional var rem:EitherType; +} + +/** + Options for one-shot `Crypto.hash`. +**/ +typedef HashOptions = { + @:optional var outputEncoding:String; + @:optional var outputLength:Int; +} + +/** + Options for `Crypto.diffieHellman`. +**/ +typedef DiffieHellmanOptions = { + var privateKey:KeyObject; + var publicKey:KeyObject; +} + +/** + Result of `Crypto.secureHeapUsed`. +**/ +typedef SecureHeapUsage = { + var total:Float; + var min:Float; + var used:Float; + var utilization:Float; +} + +/** + Result of `Crypto.encapsulate`. +**/ +typedef EncapsulateResult = { + var sharedKey:Buffer; + var ciphertext:Buffer; +} + +/** + Argon2 algorithm identifiers. +**/ +enum abstract Argon2Algorithm(String) from String to String { + var Argon2d = "argon2d"; + var Argon2i = "argon2i"; + var Argon2id = "argon2id"; +} + +/** + Parameters for `Crypto.argon2` / `argon2Sync`. +**/ +typedef Argon2Parameters = { + var message:EitherType>; + var nonce:EitherType>; + var parallelism:Int; + var tagLength:Int; + var memory:Int; + var passes:Int; + @:optional var secret:EitherType>; + @:optional var associatedData:EitherType>; +} diff --git a/src/js/node/DiagnosticsChannel.hx b/src/js/node/DiagnosticsChannel.hx new file mode 100644 index 00000000..7b4a815c --- /dev/null +++ b/src/js/node/DiagnosticsChannel.hx @@ -0,0 +1,91 @@ +/* + * Copyright (C)2014-2020 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package js.node; + +import haxe.extern.EitherType; +import js.node.diagnostics_channel.Channel; +import js.node.diagnostics_channel.Channel.ChannelListener; +import js.node.diagnostics_channel.Channel.ChannelName; +import js.node.diagnostics_channel.TracingChannel; +import js.node.diagnostics_channel.TracingChannel.TracingChannelChannels; + +/** + The `diagnostics_channel` module provides an API to create named channels + to report arbitrary message data for diagnostics purposes. + + @see https://nodejs.org/docs/latest-v24.x/api/diagnostics_channel.html +**/ +@:jsRequire("diagnostics_channel") +extern class DiagnosticsChannel { + /** + Check if there are active subscribers to the named channel. + This is helpful if the message you want to send might be expensive to prepare. + + This API is optional but helpful when trying to publish messages from very + performance-sensitive code. + + @see https://nodejs.org/docs/latest-v24.x/api/diagnostics_channel.html#diagnostics_channelhassubscribersname + **/ + static function hasSubscribers(name:ChannelName):Bool; + + /** + This is the primary entry-point for anyone wanting to publish to a named channel. + It produces a channel object which is optimized to reduce overhead at publish time + as much as possible. + + @see https://nodejs.org/docs/latest-v24.x/api/diagnostics_channel.html#diagnostics_channelchannelname + **/ + static function channel(name:ChannelName):Channel; + + /** + Register a message handler to subscribe to this channel. + This message handler will be run synchronously whenever a message is published + to the channel. Any errors thrown in the message handler will trigger an + `'uncaughtException'`. + + @see https://nodejs.org/docs/latest-v24.x/api/diagnostics_channel.html#diagnostics_channelsubscribename-onmessage + **/ + static function subscribe(name:ChannelName, onMessage:ChannelListener):Void; + + /** + Remove a message handler previously registered to this channel with + `DiagnosticsChannel.subscribe(name, onMessage)`. + + Returns `true` if the handler was found, `false` otherwise. + + @see https://nodejs.org/docs/latest-v24.x/api/diagnostics_channel.html#diagnostics_channelunsubscribename-onmessage + **/ + static function unsubscribe(name:ChannelName, onMessage:ChannelListener):Bool; + + /** + Creates a `TracingChannel` wrapper for the given TracingChannel Channels. + If a name is given, the corresponding tracing channels will be created in the + form of `tracing:${name}:${eventType}` where `eventType` corresponds to the + types of TracingChannel Channels. + + Stability: 1 - Experimental + + @see https://nodejs.org/docs/latest-v24.x/api/diagnostics_channel.html#diagnostics_channeltracingchannelnameorchannels + **/ + static function tracingChannel(nameOrChannels:EitherType):TracingChannel; +} diff --git a/src/js/node/Dns.hx b/src/js/node/Dns.hx index 8a09041e..24fc1ba6 100644 --- a/src/js/node/Dns.hx +++ b/src/js/node/Dns.hx @@ -23,11 +23,9 @@ package js.node; import haxe.extern.EitherType; -#if haxe4 +import js.node.dns.Resolver as ResolverObject; +import js.lib.ArrayBuffer; import js.lib.Error; -#else -import js.Error; -#end /** Enumeration of possible Int `options` values for `Dns.lookup`. @@ -37,14 +35,26 @@ enum abstract DnsAddressFamily(Int) from Int to Int { var IPv6 = 6; } +/** + Values for the `order` option of `Dns.lookup` / `DnsPromises.lookup` + and for `Dns.setDefaultResultOrder` / `Dns.getDefaultResultOrder`. +**/ +enum abstract DnsResultOrder(String) from String to String { + var Ipv4First = "ipv4first"; + var Ipv6First = "ipv6first"; + var Verbatim = "verbatim"; +} + /** Type of the `options` argument for `Dns.lookup`. **/ typedef DnsLookupOptions = { /** - The record family. If not provided, both IP v4 and v6 addresses are accepted. + The record family. Must be `4`, `6`, or `0`. + For compatibility, `'IPv4'` and `'IPv6'` are also accepted. + The value `0` indicates that either an IPv4 or IPv6 address is returned. **/ - @:optional var family:DnsAddressFamily; + @:optional var family:EitherType; /** If present, it should be one or more of the supported `getaddrinfo` flags. @@ -58,6 +68,52 @@ typedef DnsLookupOptions = { Defaults to false. **/ @:optional var all:Bool; + + /** + When `verbatim`, the resolved addresses are returned unsorted. + When `ipv4first` / `ipv6first`, addresses are sorted accordingly. + Default is configurable via `Dns.setDefaultResultOrder`. + **/ + @:optional var order:DnsResultOrder; + + /** + When `true`, the callback receives IPv4 and IPv6 addresses in the order the DNS resolver returned them. + When `false`, IPv4 addresses are placed before IPv6 addresses. + + Deprecated in favor of `order`. When both are specified, `order` has higher precedence. + **/ + @:optional var verbatim:Bool; +} + +/** + Options for `Dns.resolve4` / `Dns.resolve6`. +**/ +typedef DnsResolveOptions = { + /** + When `true`, each record includes its TTL (in seconds). + **/ + @:optional var ttl:Bool; +} + +/** + Options for constructing a `dns.Resolver`. +**/ +typedef DnsResolverOptions = { + /** + Query timeout in milliseconds, or `-1` to use the default timeout. + **/ + @:optional var timeout:Int; + + /** + The number of tries the resolver will try contacting each name server before giving up. + Default: `4`. + **/ + @:optional var tries:Int; + + /** + The max retry timeout, in milliseconds. Default: `0` (disabled). + **/ + @:optional var maxTimeout:Int; } /** @@ -74,6 +130,16 @@ enum abstract DnsRrtype(String) from String to String { **/ var AAAA = "AAAA"; + /** + any records + **/ + var ANY = "ANY"; + + /** + CA authorization records + **/ + var CAA = "CAA"; + /** mail exchange records **/ @@ -89,11 +155,21 @@ enum abstract DnsRrtype(String) from String to String { **/ var SRV = "SRV"; + /** + certificate associations + **/ + var TLSA = "TLSA"; + /** used for reverse IP lookups **/ var PTR = "PTR"; + /** + name authority pointer records + **/ + var NAPTR = "NAPTR"; + /** name server records **/ @@ -117,7 +193,116 @@ typedef DnsResolvedAddressMX = {priority:Int, exchange:String}; typedef DnsResolvedAddressSRV = {priority:Int, weight:Int, port:Int, name:String}; typedef DnsResolvedAddressSOA = {nsname:String, hostmaster:String, serial:Int, refresh:Int, retry:Int, expire:Int, minttl:Int}; -typedef DnsResolvedAddress = EitherType>>; + +typedef DnsResolvedAddressCAA = { + var critical:Int; + @:optional var issue:String; + @:optional var issuewild:String; + @:optional var iodef:String; + @:optional var contactemail:String; + @:optional var contactphone:String; +}; + +typedef DnsResolvedAddressNAPTR = { + var flags:String; + var service:String; + var regexp:String; + var replacement:String; + var order:Int; + var preference:Int; +}; + +typedef DnsResolvedAddressTLSA = { + var certUsage:Int; + var selector:Int; + var match:Int; + var data:ArrayBuffer; +}; + +/** + Address record that includes TTL, returned by `resolve4`/`resolve6` when `ttl` is true. +**/ +typedef DnsRecordWithTtl = { + var address:String; + var ttl:Int; +}; + +typedef DnsAnyARecord = { + > DnsRecordWithTtl, + var type:String; +}; + +typedef DnsAnyAaaaRecord = { + > DnsRecordWithTtl, + var type:String; +}; + +typedef DnsAnyCaaRecord = { + > DnsResolvedAddressCAA, + var type:String; +}; + +typedef DnsAnyMxRecord = { + > DnsResolvedAddressMX, + var type:String; +}; + +typedef DnsAnyNaptrRecord = { + > DnsResolvedAddressNAPTR, + var type:String; +}; + +typedef DnsAnySoaRecord = { + > DnsResolvedAddressSOA, + var type:String; +}; + +typedef DnsAnySrvRecord = { + > DnsResolvedAddressSRV, + var type:String; +}; + +typedef DnsAnyTlsaRecord = { + > DnsResolvedAddressTLSA, + var type:String; +}; + +typedef DnsAnyTxtRecord = { + var type:String; + var entries:Array; +}; + +typedef DnsAnyNsRecord = { + var type:String; + var value:String; +}; + +typedef DnsAnyPtrRecord = { + var type:String; + var value:String; +}; + +typedef DnsAnyCnameRecord = { + var type:String; + var value:String; +}; + +typedef DnsAnyRecord = EitherType>>>>>>>>>>; + +typedef DnsResolvedAddress = EitherType>>>>>; /** Error objects returned by dns lookups are of this type @@ -255,11 +440,11 @@ extern enum abstract DnsErrorCode(String) { var CANCELLED; } -typedef DnsLookupCallbackSingle = #if (haxe_ver >= 4) (err:DnsError, address:String, - family:DnsAddressFamily) -> Void; #else DnsError->String->DnsAddressFamily->Void #end +typedef DnsLookupCallbackSingle = (err:DnsError, address:String, + family:DnsAddressFamily) -> Void; -typedef DnsLookupCallbackAll = #if (haxe_ver >= 4) (err:DnsError, - addresses:Array) -> Void; #else DnsError->Array->Void; #end +typedef DnsLookupCallbackAll = (err:DnsError, + addresses:Array) -> Void; typedef DnsLookupCallbackAllEntry = {address:String, family:DnsAddressFamily}; @@ -276,6 +461,8 @@ typedef DnsLookupCallbackAllEntry = {address:String, family:DnsAddressFamily}; These functions do not use the same set of configuration files than what `lookup` uses. For instance, they do not use the configuration from /etc/hosts. These functions should be used by developers who do not want to use the underlying operating system's facilities for name resolution, and instead want to always perform DNS queries. + + @see https://nodejs.org/docs/latest-v24.x/api/dns.html **/ @:jsRequire("dns") extern class Dns { @@ -321,6 +508,13 @@ extern class Dns { **/ static var V4MAPPED(default, null):Int; + /** + A flag passed in the `hints` argument of `lookup` method. + + If `V4MAPPED` is specified, return resolved IPv6 addresses as well as IPv4 mapped IPv6 addresses. + **/ + static var ALL(default, null):Int; + /** Resolves the given `address` and `port` into a hostname and service using `getnameinfo`. @@ -346,14 +540,32 @@ extern class Dns { /** The same as `resolve`, but only for IPv4 queries (A records). `addresses` is an array of IPv4 addresses (e.g. ['74.125.79.104', '74.125.79.105', '74.125.79.106']). + + When `options.ttl` is `true`, each entry is `{ address, ttl }` instead of a string. **/ + @:overload(function(hostname:String, options:DnsResolveOptions, + callback:DnsError->EitherType, Array>->Void):Void {}) static function resolve4(hostname:String, callback:DnsError->Array->Void):Void; /** The same as `resolve4` except for IPv6 queries (an AAAA query). + + When `options.ttl` is `true`, each entry is `{ address, ttl }` instead of a string. **/ + @:overload(function(hostname:String, options:DnsResolveOptions, + callback:DnsError->EitherType, Array>->Void):Void {}) static function resolve6(hostname:String, callback:DnsError->Array->Void):Void; + /** + Uses the DNS protocol to resolve all records (also known as `ANY` or `*` query). + **/ + static function resolveAny(hostname:String, callback:DnsError->Array->Void):Void; + + /** + Uses the DNS protocol to resolve `CAA` records for the `hostname`. + **/ + static function resolveCaa(hostname:String, callback:DnsError->Array->Void):Void; + /** The same as `resolve`, but only for mail exchange queries (MX records). `addresses` is an array of MX records, each with a priority @@ -361,6 +573,11 @@ extern class Dns { **/ static function resolveMx(hostname:String, callback:DnsError->Array->Void):Void; + /** + Uses the DNS protocol to resolve regular expression-based records (`NAPTR` records) for the `hostname`. + **/ + static function resolveNaptr(hostname:String, callback:DnsError->Array->Void):Void; + /** The same as `resolve`, but only for text queries (TXT records). `addresses` is a 2-d array of the text records available for hostname (e.g., [ ['v=spf1 ip4:0.0.0.0 ', '~all' ] ]). @@ -377,6 +594,11 @@ extern class Dns { **/ static function resolveSrv(hostname:String, callback:DnsError->Array->Void):Void; + /** + Uses the DNS protocol to resolve certificate associations (`TLSA` records) for the `hostname`. + **/ + static function resolveTlsa(hostname:String, callback:DnsError->Array->Void):Void; + /** Uses the DNS protocol to resolve pointer records (PTR records) for the `hostname`. The addresses argument passed to the callback function will be an array of strings containing the reply records. @@ -430,4 +652,21 @@ extern class Dns { This will throw if you pass invalid input. **/ static function setServers(servers:Array):Void; + + /** + Get the default value for `order` in `Dns.lookup` and `DnsPromises.lookup`. + **/ + static function getDefaultResultOrder():DnsResultOrder; + + /** + Set the default value of `order` in `Dns.lookup` and `DnsPromises.lookup`. + **/ + static function setDefaultResultOrder(order:DnsResultOrder):Void; + + /** + `Resolver` class constructor for an independent DNS resolver. + + @see https://nodejs.org/docs/latest-v24.x/api/dns.html#class-dnsresolver + **/ + static var Resolver:Class; } diff --git a/src/js/node/DnsPromises.hx b/src/js/node/DnsPromises.hx new file mode 100644 index 00000000..0d038dd0 --- /dev/null +++ b/src/js/node/DnsPromises.hx @@ -0,0 +1,184 @@ +/* + * Copyright (C)2014-2020 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package js.node; + +import haxe.extern.EitherType; +import js.node.Dns; +import js.node.dns.PromisesResolver as PromisesResolverObject; +import js.lib.Promise; + +/** + The `dns/promises` API provides an alternative set of asynchronous DNS methods + that return `Promise` objects rather than using callbacks. + + The API is accessible via `require('dns/promises')` or `require('dns').promises`. + + `ADDRCONFIG`, `V4MAPPED`, and `ALL` are not exported by `dns/promises` (they are `undefined` + there). For lookup `hints`, use `Dns.ADDRCONFIG`, `Dns.V4MAPPED`, and `Dns.ALL`. + + @see https://nodejs.org/docs/latest-v24.x/api/dns.html#dns-promises-api +**/ +@:jsRequire("dns/promises") +extern class DnsPromises { + /** + Returns an array of IP address strings, formatted according to + [RFC 5952](https://tools.ietf.org/html/rfc5952), that are currently configured for DNS resolution. + **/ + static function getServers():Array; + + /** + Resolves a `hostname` into the first found A (IPv4) or AAAA (IPv6) record. + + With `all: false` (default), fulfills with `{ address, family }`. + With `all: true`, fulfills with an array of such objects. + **/ + @:overload(function(hostname:String):Promise {}) + @:overload(function(hostname:String, options:DnsAddressFamily):Promise {}) + @:overload(function(hostname:String, options:{family:EitherType, ?hints:Int, all:Bool, ?order:DnsResultOrder, ?verbatim:Bool}):Promise> {}) + static function lookup(hostname:String, options:EitherType):Promise>>; + + /** + Resolves the given `address` and `port` into a hostname and service using `getnameinfo`. + **/ + static function lookupService(address:String, port:Int):Promise; + + /** + Uses the DNS protocol to resolve a hostname into an array of the record types specified by `rrtype`. + **/ + @:overload(function(hostname:String):Promise> {}) + static function resolve(hostname:String, rrtype:DnsRrtype):Promise>; + + /** + Uses the DNS protocol to resolve IPv4 addresses (`A` records) for the `hostname`. + + When `options.ttl` is `true`, each entry is `{ address, ttl }` instead of a string. + **/ + @:overload(function(hostname:String, options:DnsResolveOptions):Promise, Array>> {}) + static function resolve4(hostname:String):Promise>; + + /** + Uses the DNS protocol to resolve IPv6 addresses (`AAAA` records) for the `hostname`. + + When `options.ttl` is `true`, each entry is `{ address, ttl }` instead of a string. + **/ + @:overload(function(hostname:String, options:DnsResolveOptions):Promise, Array>> {}) + static function resolve6(hostname:String):Promise>; + + /** + Uses the DNS protocol to resolve all records (also known as `ANY` or `*` query). + **/ + static function resolveAny(hostname:String):Promise>; + + /** + Uses the DNS protocol to resolve `CAA` records for the `hostname`. + **/ + static function resolveCaa(hostname:String):Promise>; + + /** + Uses the DNS protocol to resolve `CNAME` records for the `hostname`. + **/ + static function resolveCname(hostname:String):Promise>; + + /** + Uses the DNS protocol to resolve mail exchange records (`MX` records) for the `hostname`. + **/ + static function resolveMx(hostname:String):Promise>; + + /** + Uses the DNS protocol to resolve regular expression-based records (`NAPTR` records) for the `hostname`. + **/ + static function resolveNaptr(hostname:String):Promise>; + + /** + Uses the DNS protocol to resolve name server records (`NS` records) for the `hostname`. + **/ + static function resolveNs(hostname:String):Promise>; + + /** + Uses the DNS protocol to resolve pointer records (`PTR` records) for the `hostname`. + **/ + static function resolvePtr(hostname:String):Promise>; + + /** + Uses the DNS protocol to resolve a start of authority record (`SOA` record) for the `hostname`. + **/ + static function resolveSoa(hostname:String):Promise; + + /** + Uses the DNS protocol to resolve service records (`SRV` records) for the `hostname`. + **/ + static function resolveSrv(hostname:String):Promise>; + + /** + Uses the DNS protocol to resolve certificate associations (`TLSA` records) for the `hostname`. + **/ + static function resolveTlsa(hostname:String):Promise>; + + /** + Uses the DNS protocol to resolve text queries (`TXT` records) for the `hostname`. + **/ + static function resolveTxt(hostname:String):Promise>>; + + /** + Performs a reverse DNS query that resolves an IPv4 or IPv6 address to an array of hostnames. + **/ + static function reverse(ip:String):Promise>; + + /** + Sets the IP address and port of servers to be used when performing DNS resolution. + **/ + static function setServers(servers:Array):Void; + + /** + Get the default value for `order` in `Dns.lookup` and `DnsPromises.lookup`. + **/ + static function getDefaultResultOrder():DnsResultOrder; + + /** + Set the default value of `order` in `Dns.lookup` and `DnsPromises.lookup`. + **/ + static function setDefaultResultOrder(order:DnsResultOrder):Void; + + /** + `Resolver` class constructor for an independent promise-based DNS resolver. + + @see https://nodejs.org/docs/latest-v24.x/api/dns.html#class-dnspromisesresolver + **/ + static var Resolver:Class; +} + +/** + Result of `DnsPromises.lookup` when `all` is not `true`. +**/ +typedef DnsPromisesLookupResult = { + var address:String; + var family:DnsAddressFamily; +} + +/** + Result of `DnsPromises.lookupService`. +**/ +typedef DnsPromisesLookupServiceResult = { + var hostname:String; + var service:String; +} diff --git a/src/js/node/Domain.hx b/src/js/node/Domain.hx index 63fac5f3..53d447cf 100644 --- a/src/js/node/Domain.hx +++ b/src/js/node/Domain.hx @@ -27,11 +27,15 @@ import js.node.domain.Domain as DomainObject; /** Domains provide a way to handle multiple different IO operations as a single group. + Stability: 0 - Deprecated. Prefer `js.node.AsyncHooks` / `AsyncLocalStorage` for async context tracking. + If any of the event emitters or callbacks registered to a domain emit an error event, or throw an error, then the domain object will be notified, rather than losing the context of the error in the process.on('uncaughtException') handler, or causing the program to exit immediately with an error code. + + @see https://nodejs.org/docs/latest-v24.x/api/domain.html **/ -@:deprecated +@:deprecated("The domain module is deprecated. Use AsyncLocalStorage / async_hooks instead.") @:jsRequire("domain") extern class Domain { /** diff --git a/src/js/node/Events.hx b/src/js/node/Events.hx index ad0e8cd9..99451599 100644 --- a/src/js/node/Events.hx +++ b/src/js/node/Events.hx @@ -1,51 +1,180 @@ -/* - * Copyright (C)2014-2020 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package js.node; - -import haxe.Constraints.Function; -import js.node.events.EventEmitter; -#if haxe4 -import js.lib.Promise; -#else -import js.Promise; -#end - -/** - Much of the Node.js core API is built around an idiomatic asynchronous event-driven architecture - in which certain kinds of objects (called "emitters") emit named events that cause `Function` objects - ("listeners") to be called. - - @see https://nodejs.org/api/events.html#events_events - */ -@:jsRequire("events") -extern class Events { - /** - Creates a `Promise` that is resolved when the `EventEmitter` emits the given - event or that is rejected when the `EventEmitter` emits `'error'`. - The `Promise` will resolve with an array of all the arguments emitted to the - given event. - - @see https://nodejs.org/api/events.html#events_events_once_emitter_name - **/ - static function once(emitter:IEventEmitter, name:Event):Promise>; -} +/* + * Copyright (C)2014-2020 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package js.node; + +import haxe.Constraints.Function; +import haxe.extern.Rest; +import js.lib.Promise; +import js.lib.Symbol; +import js.node.events.EventEmitter; +import js.node.web.AbortSignal; + +/** + Much of the Node.js core API is built around an idiomatic asynchronous event-driven architecture + in which certain kinds of objects (called "emitters") emit named events that cause `Function` objects + ("listeners") to be called. + + @see https://nodejs.org/api/events.html#events_events + */ +@:jsRequire("events") +extern class Events { + /** + This symbol shall be used to install a listener for only monitoring `'error'` + events. Listeners installed using this symbol are called before the regular + `'error'` listeners are called. + + @see https://nodejs.org/api/events.html#eventserrormonitor + **/ + static final errorMonitor:Symbol; + + /** + Value: `Symbol.for('nodejs.rejection')` + + @see https://nodejs.org/api/events.html#eventscapturerejectionsymbol + **/ + static final captureRejectionSymbol:Symbol; + + /** + Change the default `captureRejections` option on all new `EventEmitter` objects. + + @see https://nodejs.org/api/events.html#eventscapturerejections + **/ + static var captureRejections:Bool; + + /** + By default, a maximum of `10` listeners can be registered for any single event. + This alias mirrors `EventEmitter.defaultMaxListeners`. + + @see https://nodejs.org/api/events.html#eventsdefaultmaxlisteners + **/ + static var defaultMaxListeners:Int; + + /** + Creates a `Promise` that is fulfilled when the `EventEmitter` emits the given + event or that is rejected if the `EventEmitter` emits `'error'` while waiting. + The `Promise` will resolve with an array of all the arguments emitted to the + given event. + + @see https://nodejs.org/api/events.html#eventsonceemitter-name-options + **/ + @:overload(function(emitter:IEventEmitter, name:Event, options:EventsOnceOptions):Promise> {}) + static function once(emitter:IEventEmitter, name:Event):Promise>; + + /** + Returns an `AsyncIterator` that iterates `eventName` events emitted by the `emitter`. + + @see https://nodejs.org/api/events.html#eventsonemitter-eventname-options + **/ + @:overload(function(emitter:IEventEmitter, eventName:Event, options:EventsOnOptions):EventsAsyncIterator {}) + static function on(emitter:IEventEmitter, eventName:Event):EventsAsyncIterator; + + /** + Listens once to the `abort` event on the provided `signal`. + + Returns a disposable that removes the abort listener when disposed. + + @see https://nodejs.org/api/events.html#eventsaddabortlistenersignal-listener + **/ + static function addAbortListener(signal:AbortSignal, listener:Function):EventsDisposable; + + /** + Returns a copy of the array of listeners for the event named `name`. + + @see https://nodejs.org/api/events.html#eventsgeteventlistenersemitter-name + **/ + static function getEventListeners(emitter:IEventEmitter, name:Event):Array; + + /** + Change the default `maxListeners` value for all `EventEmitter` instances, + and optionally apply that change to the given emitters. + + @see https://nodejs.org/api/events.html#eventssetmaxlistenersn-eventtargets + **/ + static function setMaxListeners(n:Int, emitters:Rest):Void; + + /** + Returns the currently set max amount of listeners for the given emitter. + + @see https://nodejs.org/api/events.html#eventsgetmaxlistenersemitterortarget + **/ + static function getMaxListeners(emitter:IEventEmitter):Int; + + /** + Returns the number of listeners for the given `eventName` registered on the + given `emitter`. + + @see https://nodejs.org/api/events.html#eventslistenercountemitterortarget-eventname + **/ + static function listenerCount(emitter:IEventEmitter, eventName:Event):Int; +} + +/** + Options for `Events.once`. +**/ +typedef EventsOnceOptions = { + /** + An `AbortSignal` that can be used to cancel waiting for the event. + **/ + @:optional var signal:AbortSignal; +} + +/** + Options for `Events.on`. +**/ +typedef EventsOnOptions = { + /** + Can be used to cancel awaiting events. + **/ + @:optional var signal:AbortSignal; + + /** + Names of events that will end the iteration. + **/ + @:optional var close:Array; + + /** + The high watermark. The emitter is paused every time the size of events + being buffered is higher than it. + **/ + @:optional var highWaterMark:Int; + + /** + The low watermark. The emitter is resumed every time the size of events + being buffered is lower than it. + **/ + @:optional var lowWaterMark:Int; +} + +/** + Minimal async iterator surface used by `Events.on` (for `for await...of`). +**/ +typedef EventsAsyncIterator = { + function next():Promise<{done:Bool, ?value:Array}>; +} + +/** + Disposable returned by `Events.addAbortListener`. +**/ +typedef EventsDisposable = { + function dispose():Void; +} diff --git a/src/js/node/Fs.hx b/src/js/node/Fs.hx index a353a428..2f0d76f2 100644 --- a/src/js/node/Fs.hx +++ b/src/js/node/Fs.hx @@ -25,15 +25,18 @@ package js.node; import haxe.DynamicAccess; import haxe.extern.EitherType; import js.node.Buffer; +import js.node.fs.Dir; +import js.node.fs.Dirent; import js.node.fs.FSWatcher; import js.node.fs.ReadStream; import js.node.fs.Stats; +import js.node.fs.StatsFs; +import js.node.fs.StatWatcher; import js.node.fs.WriteStream; -#if haxe4 import js.lib.Error; -#else -import js.Error; -#end +import js.lib.Promise; +import js.node.web.Blob; +import js.node.url.URL; /** Most FS functions now support passing `String` and `Buffer`. @@ -84,6 +87,12 @@ typedef FsWriteFileOptions = { default: 'w' for `Fs.writeFile`, 'a' for `Fs.appendFile` **/ @:optional var flag:FsOpenFlag; + + /** + If `true`, the underlying file descriptor is flushed prior to closing it. + Default: `false`. + **/ + @:optional var flush:Bool; } /** @@ -463,6 +472,26 @@ typedef FsConstants = { File mode indicating executable by others. **/ var S_IXOTH:Int; + + /** + Constant for `Fs.copyFile`. + If present, the copy operation will fail with an error if the destination path already exists. + **/ + var COPYFILE_EXCL:Int; + + /** + Constant for `Fs.copyFile`. + If present, the copy operation will attempt to create a copy-on-write reflink. + If the underlying platform does not support copy-on-write, then a fallback copy mechanism is used. + **/ + var COPYFILE_FICLONE:Int; + + /** + Constant for `Fs.copyFile`. + If present, the copy operation will attempt to create a copy-on-write reflink. + If the underlying platform does not support copy-on-write, then the operation will fail with an error. + **/ + var COPYFILE_FICLONE_FORCE:Int; } /** @@ -491,6 +520,184 @@ typedef FsRmdirOptions = { @:optional var retryDelay:Int; } +/** + Options for `Fs.rm` and `Fs.rmSync`. +**/ +typedef FsRmOptions = { + /** + When `true`, exceptions will be ignored if `path` does not exist. + Default: `false`. + **/ + @:optional var force:Bool; + + /** + If an `EBUSY`, `EMFILE`, `ENFILE`, `ENOTEMPTY`, or `EPERM` error is encountered, + Node.js will retry the operation with a linear backoff wait of `retryDelay` ms longer on each try. + This option represents the number of retries. + This option is ignored if the `recursive` option is not `true`. + Default: `0`. + **/ + @:optional var maxRetries:Int; + + /** + If `true`, perform a recursive removal. + In recursive mode, operations are retried on failure. + Default: `false`. + **/ + @:optional var recursive:Bool; + + /** + The amount of time in milliseconds to wait between retries. + This option is ignored if the `recursive` option is not `true`. + Default: `100`. + **/ + @:optional var retryDelay:Int; +} + +/** + Options for `Fs.cp` and `Fs.cpSync`. +**/ +typedef FsCpOptions = { + /** + Dereference symlinks. + Default: `false`. + **/ + @:optional var dereference:Bool; + + /** + When `force` is `false`, and the destination exists, throw an error. + Default: `false`. + **/ + @:optional var errorOnExist:Bool; + + /** + Function to filter copied files/directories. + Return `true` to copy the item, `false` to ignore it. + When ignoring a directory, all of its contents will be skipped as well. + **/ + @:optional var filter:String->String->Bool; + + /** + Overwrite existing file or directory. + The copy operation will ignore errors if you set this to `false` and the destination exists. + Use the `errorOnExist` option to change this behavior. + Default: `true`. + **/ + @:optional var force:Bool; + + /** + Modifiers for copy operation. + Default: `0`. + See `mode` flag of `Fs.copyFile`. + **/ + @:optional var mode:Int; + + /** + When `true`, timestamps from `src` will be preserved. + Default: `false`. + **/ + @:optional var preserveTimestamps:Bool; + + /** + Copy directories recursively. + Default: `false`. + **/ + @:optional var recursive:Bool; + + /** + When `true`, path resolution for symlinks will be skipped. + Default: `false`. + **/ + @:optional var verbatimSymlinks:Bool; +} + +/** + Options for `Fs.opendir` and `Fs.opendirSync`. +**/ +typedef FsOpendirOptions = { + /** + Encoding for the path while opening the directory and subsequent read operations. + Default: `'utf8'`. + **/ + @:optional var encoding:String; + + /** + Number of directory entries that are buffered internally when reading from the directory. + Higher values lead to better performance but higher memory usage. + Default: `32`. + **/ + @:optional var bufferSize:Int; + + /** + When `true`, reads the directory recursively. + Default: `false`. + **/ + @:optional var recursive:Bool; +} + +/** + Options for `Fs.glob` and `Fs.globSync`. +**/ +typedef FsGlobOptions = { + /** + Current working directory. + Default: `process.cwd()`. + **/ + @:optional var cwd:EitherType; + + /** + Function to filter out files/directories, or a list of glob patterns to be excluded. + If a function is provided, return `true` to exclude the item, `false` to include it. + **/ + @:optional var exclude:EitherTypeBool, Array>; + + /** + When `true`, symbolic links to directories are followed while expanding `**` patterns. + Default: `false`. + **/ + @:optional var followSymlinks:Bool; + + /** + `true` if the glob should return paths as `Dirent`s, `false` otherwise. + Default: `false`. + **/ + @:optional var withFileTypes:Bool; +} + +/** + Disposable temporary directory returned by `Fs.mkdtempDisposableSync`. +**/ +typedef FsMkdtempDisposable = { + /** + The path of the created directory. + **/ + var path:String; + + /** + Removes the created directory and its contents. + Same as the `[Symbol.dispose]` method on the returned object. + **/ + function remove():Void; +} + +/** + Options for `Fs.openAsBlob`. +**/ +typedef FsOpenAsBlobOptions = { + /** + An optional MIME type for the blob. + **/ + @:optional var type:String; +} + +/** + A buffer for `Fs.readv` / `Fs.writev`. + + Node.js accepts an `ArrayBufferView` (Buffer, TypedArray, or DataView). + This library follows the existing `Fs.read` / `Fs.write` convention of typing these as `Buffer`. +**/ +typedef FsVectorBuffer = Buffer; + /** File I/O is provided by simple wrappers around standard POSIX functions. All the methods have asynchronous and synchronous forms. @@ -511,6 +718,15 @@ extern class Fs { **/ static var constants(default, null):FsConstants; + /** + Promise-based file system methods (`require('fs').promises`). + Same module object as `js.node.FsPromises`. + + Prefer calling static methods on `FsPromises` for Haxe typing of overloads. + **/ + // TODO(section-2): value type mirroring FsPromises static surface (static-method extern cannot be reused as value type) + static var promises(default, null):Dynamic; + /** Asynchronous rename(2). **/ @@ -521,6 +737,45 @@ extern class Fs { **/ static function renameSync(oldPath:FsPath, newPath:FsPath):Void; + /** + Asynchronously copies `src` to `dest`. + By default, `dest` is overwritten if it already exists. + + No arguments other than a possible exception are given to the callback function. + + `mode` is an optional integer that specifies the behavior of the copy operation. + It is possible to create a mask consisting of the bitwise OR of two or more values + (e.g. `Fs.constants.COPYFILE_EXCL | Fs.constants.COPYFILE_FICLONE`). + **/ + @:overload(function(src:FsPath, dest:FsPath, callback:Error->Void):Void {}) + static function copyFile(src:FsPath, dest:FsPath, mode:Int, callback:Error->Void):Void; + + /** + Synchronously copies `src` to `dest`. + By default, `dest` is overwritten if it already exists. + + `mode` is an optional integer that specifies the behavior of the copy operation. + See `copyFile` for details. + **/ + @:overload(function(src:FsPath, dest:FsPath):Void {}) + static function copyFileSync(src:FsPath, dest:FsPath, mode:Int):Void; + + /** + Asynchronously copies the entire directory structure from `src` to `dest`, + including subdirectories and files. + + When copying a directory to another directory, globs are not supported and + behavior is similar to `cp dir1/ dir2/`. + **/ + @:overload(function(src:FsPath, dest:FsPath, callback:Error->Void):Void {}) + static function cp(src:FsPath, dest:FsPath, options:FsCpOptions, callback:Error->Void):Void; + + /** + Synchronously copies the entire directory structure from `src` to `dest`, + including subdirectories and files. + **/ + static function cpSync(src:FsPath, dest:FsPath, ?options:FsCpOptions):Void; + /** Asynchronous ftruncate(2). **/ @@ -638,6 +893,20 @@ extern class Fs { **/ static function fstatSync(fd:Int):Stats; + /** + Asynchronous statfs(2). + Returns information about the mounted file system which contains `path`. + + The callback gets two arguments `(err, stats)` where `stats` is a `StatsFs` object. + **/ + static function statfs(path:FsPath, callback:Error->StatsFs->Void):Void; + + /** + Synchronous statfs(2). + Returns information about the mounted file system which contains `path`. + **/ + static function statfsSync(path:FsPath):StatsFs; + /** Asynchronous link(2). **/ @@ -686,6 +955,7 @@ extern class Fs { `cache` is an object literal of mapped paths that can be used to force a specific path resolution or avoid additional `stat` calls for known real paths. **/ + // TODO(section-2): model `realpath.native` / `realpathSync.native` function properties @:overload(function(path:FsPath, callback:Error->String->Void):Void {}) static function realpath(path:FsPath, cache:DynamicAccess, callback:Error->String->Void):Void; @@ -706,6 +976,22 @@ extern class Fs { **/ static function unlinkSync(path:FsPath):Void; + /** + Asynchronously removes files and directories (modeled on the standard POSIX `rm` utility). + + No arguments other than a possible exception are given to the completion callback. + + To get a behavior similar to the `rm -rf` Unix command, use `Fs.rm` with options + `{ recursive: true, force: true }`. + **/ + @:overload(function(path:FsPath, callback:Error->Void):Void {}) + static function rm(path:FsPath, options:FsRmOptions, callback:Error->Void):Void; + + /** + Synchronously removes files and directories (modeled on the standard POSIX `rm` utility). + **/ + static function rmSync(path:FsPath, ?options:FsRmOptions):Void; + /** Asynchronous rmdir(2). **/ @@ -736,6 +1022,7 @@ extern class Fs { The created folder path is passed as a string to the `callback`'s second parameter. **/ + @:overload(function(prefix:String, options:EitherType, callback:Error->String->Void):Void {}) static function mkdtemp(prefix:String, callback:Error->String->Void):Void; /** @@ -743,7 +1030,19 @@ extern class Fs { Returns the created folder path. **/ - static function mkdtempSync(template:String):String; + @:overload(function(prefix:String, options:EitherType):String {}) + static function mkdtempSync(prefix:String):String; + + /** + Synchronously creates a unique temporary directory and returns a disposable object. + + When the object is disposed (or `remove` is called), the directory and its contents are removed + if they still exist. + + @see https://nodejs.org/api/fs.html#fsmkdtempdisposablesyncprefix-options + **/ + @:overload(function(prefix:String, options:EitherType):FsMkdtempDisposable {}) + static function mkdtempDisposableSync(prefix:String):FsMkdtempDisposable; /** Asynchronous readdir(3). @@ -760,6 +1059,55 @@ extern class Fs { **/ static function readdirSync(path:FsPath):Array; + /** + Asynchronously open a directory for iterative scanning. + See the POSIX opendir(3) documentation for more details. + + Creates a `Dir`, which contains all further functions for reading from + and cleaning up the directory. + + The `callback` gets two arguments `(err, dir)`. + **/ + @:overload(function(path:FsPath, callback:Error->Dir->Void):Void {}) + static function opendir(path:FsPath, options:FsOpendirOptions, callback:Error->Dir->Void):Void; + + /** + Synchronously open a directory. + See `opendir` for more details. + **/ + static function opendirSync(path:FsPath, ?options:FsOpendirOptions):Dir; + + /** + Retrieves the files matching the specified pattern. + + The `callback` gets two arguments `(err, matches)`. + When `options.withFileTypes` is `true`, `matches` is an array of `Dirent` objects; + otherwise it is an array of path strings. + **/ + @:overload(function(pattern:EitherType>, callback:Error->Array->Void):Void {}) + @:overload(function(pattern:EitherType>, options:FsGlobOptions, callback:Error->Array->Void):Void {}) + static function glob(pattern:EitherType>, options:{ + ?cwd:EitherType, + ?exclude:EitherTypeBool, Array>, + ?followSymlinks:Bool, + withFileTypes:Bool + }, callback:Error->Array->Void):Void; + + /** + Synchronously retrieves the files matching the specified pattern. + + When `options.withFileTypes` is `true`, returns an array of `Dirent` objects; + otherwise returns an array of path strings. + **/ + @:overload(function(pattern:EitherType>):Array {}) + @:overload(function(pattern:EitherType>, options:FsGlobOptions):Array {}) + static function globSync(pattern:EitherType>, options:{ + ?cwd:EitherType, + ?exclude:EitherTypeBool, Array>, + ?followSymlinks:Bool, + withFileTypes:Bool + }):Array; + /** Asynchronous close(2). **/ @@ -789,6 +1137,17 @@ extern class Fs { @:overload(function(path:FsPath, flags:FsOpenFlag):Int {}) static function openSync(path:FsPath, flags:FsOpenFlag, mode:FsMode):Int; + /** + Returns a `Blob` whose data is backed by the given file. + + The file must not be modified after the `Blob` is created. + Any modifications will cause reading the `Blob` data to fail with a `DOMException` error. + + @see https://nodejs.org/api/fs.html#fsopenasblobpath-options + **/ + @:overload(function(path:FsPath):Promise {}) + static function openAsBlob(path:FsPath, options:FsOpenAsBlobOptions):Promise; + /** Change file timestamps of the file referenced by the supplied path. **/ @@ -809,6 +1168,20 @@ extern class Fs { **/ static function futimesSync(fd:Int, atime:Date, mtime:Date):Void; + /** + Change the file system timestamps of the symbolic link referenced by `path`. + + Same as `utimes`, except that if the path refers to a symbolic link, + then the link is not dereferenced: instead, the timestamps of the symbolic link itself are changed. + **/ + static function lutimes(path:FsPath, atime:Date, mtime:Date, callback:Error->Void):Void; + + /** + Change the file system timestamps of the symbolic link referenced by `path`. + This is the synchronous version of `lutimes`. + **/ + static function lutimesSync(path:FsPath, atime:Date, mtime:Date):Void; + /** Asynchronous fsync(2). **/ @@ -819,6 +1192,22 @@ extern class Fs { **/ static function fsyncSync(fd:Int):Void; + /** + Asynchronous fdatasync(2). + + Forces all currently queued I/O operations associated with the file to the + operating system's synchronized I/O completion state. + Refer to the POSIX fdatasync(2) documentation for details. + + No arguments other than a possible exception are given to the completion callback. + **/ + static function fdatasync(fd:Int, callback:Error->Void):Void; + + /** + Synchronous fdatasync(2). + **/ + static function fdatasyncSync(fd:Int):Void; + /** Documentation for the overloads with the `buffer` argument: @@ -861,19 +1250,36 @@ extern class Fs { On Linux, positional writes don't work when the file is opened in append mode. The kernel ignores the position argument and always appends the data to the end of the file. **/ - @:overload(function(fd:Int, data:Dynamic, position:Int, encoding:String, callback:Error->Int->String->Void):Void {}) - @:overload(function(fd:Int, data:Dynamic, position:Int, callback:Error->Int->String->Void):Void {}) - @:overload(function(fd:Int, data:Dynamic, callback:Error->Int->String->Void):Void {}) + @:overload(function(fd:Int, data:String, position:Int, encoding:String, callback:Error->Int->String->Void):Void {}) + @:overload(function(fd:Int, data:String, position:Int, callback:Error->Int->String->Void):Void {}) + @:overload(function(fd:Int, data:String, callback:Error->Int->String->Void):Void {}) @:overload(function(fd:Int, buffer:Buffer, offset:Int, length:Int, callback:Error->Int->Buffer->Void):Void {}) static function write(fd:Int, buffer:Buffer, offset:Int, length:Int, position:Int, callback:Error->Int->Buffer->Void):Void; /** Synchronous version of `write`. Returns the number of bytes written. **/ - @:overload(function(fd:Int, data:Dynamic, position:Int, encoding:String):Int {}) - @:overload(function(fd:Int, data:Dynamic, ?position:Int):Int {}) + @:overload(function(fd:Int, data:String, position:Int, encoding:String):Int {}) + @:overload(function(fd:Int, data:String, ?position:Int):Int {}) static function writeSync(fd:Int, buffer:Buffer, offset:Int, length:Int, ?position:Int):Int; + /** + Write an array of buffers to the file specified by `fd` using writev(). + + `position` is the offset from the beginning of the file where this data should be written. + If `position` is not a number, the data will be written at the current position. + + The callback will be given three arguments: `(err, bytesWritten, buffers)`. + `bytesWritten` is how many bytes were written from `buffers`. + **/ + @:overload(function(fd:Int, buffers:Array, callback:Error->Int->Array->Void):Void {}) + static function writev(fd:Int, buffers:Array, position:Int, callback:Error->Int->Array->Void):Void; + + /** + Synchronous version of `writev`. Returns the number of bytes written. + **/ + static function writevSync(fd:Int, buffers:Array, ?position:Int):Int; + /** Read data from the file specified by `fd`. @@ -895,6 +1301,23 @@ extern class Fs { **/ static function readSync(fd:Int, buffer:Buffer, offset:Int, length:Int, position:Null):Int; + /** + Read from a file specified by `fd` and write to an array of buffers using readv(). + + `position` is the offset from the beginning of the file from where data should be read. + If `position` is not a number, the data will be read from the current position. + + The callback will be given three arguments: `(err, bytesRead, buffers)`. + `bytesRead` is how many bytes were read from the file. + **/ + @:overload(function(fd:Int, buffers:Array, callback:Error->Int->Array->Void):Void {}) + static function readv(fd:Int, buffers:Array, position:Int, callback:Error->Int->Array->Void):Void; + + /** + Synchronous version of `readv`. Returns the number of bytes read. + **/ + static function readvSync(fd:Int, buffers:Array, ?position:Int):Int; + /** Asynchronously reads the entire contents of a file. @@ -967,8 +1390,8 @@ extern class Fs { The `listener` gets two arguments: the current stat object and the previous stat object. **/ - @:overload(function(filename:FsPath, listener:Stats->Stats->Void):Void {}) - static function watchFile(filename:FsPath, options:FsWatchFileOptions, listener:Stats->Stats->Void):Void; + @:overload(function(filename:FsPath, listener:Stats->Stats->Void):StatWatcher {}) + static function watchFile(filename:FsPath, options:FsWatchFileOptions, listener:Stats->Stats->Void):StatWatcher; /** Unstable. Use `watch` instead, if possible. @@ -1038,6 +1461,7 @@ extern class Fs { File is visible to the calling process. This is useful for determining if a file exists, but says nothing about rwx permissions. **/ + @:deprecated("Use Fs.constants.F_OK instead") static var F_OK(default, null):Int; /** @@ -1045,6 +1469,7 @@ extern class Fs { File can be read by the calling process. **/ + @:deprecated("Use Fs.constants.R_OK instead") static var R_OK(default, null):Int; /** @@ -1052,6 +1477,7 @@ extern class Fs { File can be written by the calling process. **/ + @:deprecated("Use Fs.constants.W_OK instead") static var W_OK(default, null):Int; /** @@ -1060,6 +1486,7 @@ extern class Fs { File can be executed by the calling process. This has no effect on Windows. **/ + @:deprecated("Use Fs.constants.X_OK instead") static var X_OK(default, null):Int; /** diff --git a/src/js/node/FsPromises.hx b/src/js/node/FsPromises.hx new file mode 100644 index 00000000..fde56d3b --- /dev/null +++ b/src/js/node/FsPromises.hx @@ -0,0 +1,323 @@ +/* + * Copyright (C)2014-2020 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package js.node; + +import haxe.extern.EitherType; +import js.node.Fs; +import js.node.fs.Dir; +import js.node.fs.Dirent; +import js.node.fs.FileHandle; +import js.node.fs.Stats; +import js.node.fs.StatsFs; +import js.lib.Promise; + +/** + Minimal async iterator surface used by `glob` / `watch` (for `for await...of`). +**/ +typedef FsPromisesAsyncIterator = { + function next():Promise<{done:Bool, ?value:T}>; +} + +/** + The `fs/promises` API provides asynchronous file system methods that return promises. + + The API is accessible via `require('fs/promises')` or `require('fs').promises`. + + @see https://nodejs.org/api/fs.html#promises-api +**/ +@:jsRequire("fs/promises") +extern class FsPromises { + /** + An object containing commonly used constants for file system operations. + Same as `Fs.constants`. + **/ + static var constants(default, null):FsConstants; + + /** + Tests a user's permissions for the file or directory specified by `path`. + **/ + @:overload(function(path:FsPath):Promise {}) + static function access(path:FsPath, mode:Int):Promise; + + /** + Asynchronously append data to a file, creating the file if it does not exist. + **/ + @:overload(function(path:EitherType, data:EitherType):Promise {}) + static function appendFile(path:EitherType, data:EitherType, + options:EitherType):Promise; + + /** + Changes file permissions of `path`. + **/ + static function chmod(path:FsPath, mode:FsMode):Promise; + + /** + Changes file ownership of `path`. + **/ + static function chown(path:FsPath, uid:Int, gid:Int):Promise; + + /** + Asynchronously copies `src` to `dest`. + **/ + @:overload(function(src:FsPath, dest:FsPath):Promise {}) + static function copyFile(src:FsPath, dest:FsPath, mode:Int):Promise; + + /** + Asynchronously copies the entire directory structure from `src` to `dest`, + including subdirectories and files. + **/ + @:overload(function(src:FsPath, dest:FsPath):Promise {}) + static function cp(src:FsPath, dest:FsPath, options:FsCpOptions):Promise; + + /** + Retrieves the files matching the specified pattern as an async iterator. + **/ + @:overload(function(pattern:EitherType>):FsPromisesAsyncIterator {}) + @:overload(function(pattern:EitherType>, options:FsGlobOptions):FsPromisesAsyncIterator {}) + static function glob(pattern:EitherType>, options:{ + ?cwd:haxe.extern.EitherType, + ?exclude:EitherTypeBool, Array>, + ?followSymlinks:Bool, + withFileTypes:Bool + }):FsPromisesAsyncIterator; + + /** + Changes the permissions on a symbolic link. + No-op on Windows. + **/ + static function lchmod(path:FsPath, mode:FsMode):Promise; + + /** + Changes the ownership on a symbolic link. + **/ + static function lchown(path:FsPath, uid:Int, gid:Int):Promise; + + /** + Changes the access and modification times of a file in the same way as `utimes`, + without following symlinks. + **/ + static function lutimes(path:FsPath, atime:EitherType>, + mtime:EitherType>):Promise; + + /** + Creates a new link from `existingPath` to `newPath`. + **/ + static function link(existingPath:FsPath, newPath:FsPath):Promise; + + /** + Retrieves the `fs.Stats` for the symbolic link referred to by `path`. + **/ + @:overload(function(path:FsPath):Promise {}) + static function lstat(path:FsPath, options:{?bigint:Bool}):Promise; + + /** + Asynchronously creates a directory. + When `recursive` is true, fulfills with the first directory path created, if any. + **/ + @:overload(function(path:FsPath):Promise> {}) + @:overload(function(path:FsPath, mode:FsMode):Promise> {}) + static function mkdir(path:FsPath, options:{?recursive:Bool, ?mode:FsMode}):Promise>; + + /** + Creates a unique temporary directory. + Generates six random characters to be appended behind a required `prefix` to create a unique temporary directory. + **/ + @:overload(function(prefix:String):Promise {}) + static function mkdtemp(prefix:String, options:EitherType):Promise; + + /** + Asynchronously creates a unique temporary directory and returns an async-disposable object. + + When the object is disposed (or `remove` is awaited), the directory and its contents are removed + if they still exist. + + @see https://nodejs.org/api/fs.html#fspromisesmkdtempdisposableprefix-options + **/ + @:overload(function(prefix:String):Promise {}) + static function mkdtempDisposable(prefix:String, options:EitherType):Promise; + + /** + Opens a `FileHandle`. + **/ + @:overload(function(path:FsPath):Promise {}) + @:overload(function(path:FsPath, flags:FsOpenFlag):Promise {}) + static function open(path:FsPath, flags:FsOpenFlag, mode:FsMode):Promise; + + /** + Asynchronously open a directory for iterative scanning. + **/ + @:overload(function(path:FsPath):Promise {}) + static function opendir(path:FsPath, options:FsOpendirOptions):Promise; + + /** + Reads the contents of a directory. + **/ + @:overload(function(path:FsPath):Promise> {}) + @:overload(function(path:FsPath, options:EitherType):Promise> {}) + static function readdir(path:FsPath, options:{?encoding:String, withFileTypes:Bool, ?recursive:Bool}):Promise>; + + /** + Asynchronously reads the entire contents of a file. + If no encoding is specified, the data is returned as a `Buffer`. + **/ + @:overload(function(path:EitherType):Promise {}) + @:overload(function(path:EitherType, options:EitherType):Promise {}) + static function readFile(path:EitherType, + ?options:{?encoding:String, ?flag:FsOpenFlag}):Promise>; + + /** + Reads the contents of the symbolic link referred to by `path`. + **/ + @:overload(function(path:FsPath):Promise {}) + static function readlink(path:FsPath, options:EitherType):Promise>; + + /** + Determines the actual location of `path` using the same semantics as the `fs.realpath` algorithm. + **/ + @:overload(function(path:FsPath):Promise {}) + static function realpath(path:FsPath, options:EitherType):Promise>; + + /** + Renames `oldPath` to `newPath`. + **/ + static function rename(oldPath:FsPath, newPath:FsPath):Promise; + + /** + Removes files and directories (modeled on the standard POSIX `rm` utility). + **/ + @:overload(function(path:FsPath):Promise {}) + static function rm(path:FsPath, options:FsRmOptions):Promise; + + /** + Removes the directory identified by `path`. + **/ + @:overload(function(path:FsPath):Promise {}) + static function rmdir(path:FsPath, options:FsRmdirOptions):Promise; + + /** + Retrieves the `fs.Stats` for the file referred to by `path`. + **/ + @:overload(function(path:FsPath):Promise {}) + static function stat(path:FsPath, options:{?bigint:Bool}):Promise; + + /** + Retrieves information about the file system containing the given `path`. + **/ + @:overload(function(path:FsPath):Promise {}) + static function statfs(path:FsPath, options:{?bigint:Bool}):Promise; + + /** + Creates a symbolic link. + **/ + @:overload(function(target:FsPath, path:FsPath):Promise {}) + static function symlink(target:FsPath, path:FsPath, type:SymlinkType):Promise; + + /** + Truncates (shortens or extends the length) of the content at `path` to be `len` bytes long. + **/ + @:overload(function(path:FsPath):Promise {}) + static function truncate(path:FsPath, len:Int):Promise; + + /** + Removes the link and deletes the file named by `path` if no other references exist. + **/ + static function unlink(path:FsPath):Promise; + + /** + Change the file system timestamps of the object referenced by `path`. + **/ + static function utimes(path:FsPath, atime:EitherType>, + mtime:EitherType>):Promise; + + /** + Returns an async iterator that watches for changes on `filename`. + **/ + @:overload(function(filename:FsPath):FsPromisesAsyncIterator {}) + static function watch(filename:FsPath, options:EitherType):FsPromisesAsyncIterator; + + /** + Asynchronously writes data to a file, replacing the file if it already exists. + **/ + @:overload(function(file:EitherType, data:EitherType):Promise {}) + static function writeFile(file:EitherType, data:EitherType, + options:EitherType):Promise; +} + +/** + Options for `FsPromises.watch`. +**/ +typedef FsPromisesWatchOptions = { + /** + Specifies the character encoding to be used for the filename passed to the listener. + Default: `'utf8'`. + **/ + @:optional var encoding:String; + + /** + Indicates whether the process should continue to run as long as files are being watched. + Default: `true`. + **/ + @:optional var persistent:Bool; + + /** + Indicates whether all files should be watched, or only the current directory. + Default: `false`. + **/ + @:optional var recursive:Bool; + + /** + Allows aborting an in-progress watch with an AbortSignal. + **/ + @:optional var signal:js.node.web.AbortSignal; +} + +/** + Event yielded by `FsPromises.watch`. +**/ +typedef FsPromisesWatchEvent = { + /** + The type of change: `'rename'` or `'change'`. + **/ + var eventType:String; + + /** + The name of the file that changed. + **/ + var filename:Null>; +} + +/** + Async-disposable temporary directory returned by `FsPromises.mkdtempDisposable`. +**/ +typedef FsPromisesMkdtempDisposable = { + /** + The path of the created directory. + **/ + var path:String; + + /** + Asynchronously removes the created directory and its contents. + Same as the `[Symbol.asyncDispose]` method on the returned object. + **/ + function remove():Promise; +} diff --git a/src/js/node/Http.hx b/src/js/node/Http.hx index f2530bfb..109a5a9c 100644 --- a/src/js/node/Http.hx +++ b/src/js/node/Http.hx @@ -28,11 +28,8 @@ import js.node.http.*; import js.node.net.Socket; import js.node.stream.Duplex; import js.node.url.URL; -#if haxe4 +import js.node.web.AbortSignal; import js.lib.Error; -#else -import js.Error; -#end /** The HTTP interfaces in Node are designed to support many features of the protocol @@ -67,13 +64,8 @@ extern class Http { The `requestListener` is a function which is automatically added to the `'request'` event. **/ - #if haxe4 @:overload(function(options:HttpCreateServerOptions, ?requestListener:(request:IncomingMessage, response:ServerResponse) -> Void):Server {}) static function createServer(?requestListener:(request:IncomingMessage, response:ServerResponse) -> Void):Server; - #else - @:overload(function(options:HttpCreateServerOptions, ?requestListener:IncomingMessage->ServerResponse->Void):Server {}) - static function createServer(?requestListener:IncomingMessage->ServerResponse->Void):Server; - #end /** Since most requests are GET requests without bodies, Node.js provides this convenience method. @@ -110,6 +102,48 @@ extern class Http { @:overload(function(url:URL, ?options:HttpRequestOptions, ?callback:IncomingMessage->Void):ClientRequest {}) @:overload(function(url:String, ?options:HttpRequestOptions, ?callback:IncomingMessage->Void):ClientRequest {}) static function request(options:HttpRequestOptions, ?callback:IncomingMessage->Void):ClientRequest; + + /** + Performs the low-level validations on the provided `name` that are done when `res.setHeader(name, value)` is called. + @throws `TypeError` if the `name` is invalid. + **/ + static function validateHeaderName(name:String, ?label:String):Void; + + /** + Performs the low-level validations on the provided `value` that are done when `res.setHeader(name, value)` is called. + @throws `TypeError` if the `value` is invalid. + **/ + static function validateHeaderValue(name:String, value:EitherType>):Void; + + /** + Set the maximum number of idle HTTP parsers that can stay around for reuse. + Default: `1000`. + **/ + static function setMaxIdleHTTPParsers(max:Int):Void; + + /** + Undici `WebSocket` constructor exposed via `node:http`. + **/ + static var WebSocket:Class; + + /** + Parent class of `http.ClientRequest` and `http.ServerResponse`. + + @see https://nodejs.org/docs/latest-v24.x/api/http.html#class-httpoutgoingmessage + **/ + static var OutgoingMessage:Class; + + /** + Dynamically resets the global configurations to enable built-in proxy support for + `fetch()` and `http.request()` / `https.request()` at runtime. + + Returns a restore function for the previous agent/dispatcher settings. + + Added in: v24.14.0. + + @see https://nodejs.org/docs/latest-v24.x/api/http.html#httpsetglobalproxyfromenvproxyenv + **/ + static function setGlobalProxyFromEnv(?proxyEnv:DynamicAccess):() -> Void; } typedef HttpCreateServerOptions = { @@ -118,14 +152,81 @@ typedef HttpCreateServerOptions = { Default: `js.node.http.IncomingMessage`. **/ - @:optional var IncomingMessage:Class; + @:optional var IncomingMessage:Class; /** Specifies the `ServerResponse` class to be used. Useful for extending the original `ServerResponse`. Default: `ServerResponse`. **/ - @:optional var ServerResponse:Class; + @:optional var ServerResponse:Class; + + /** + Sets the timeout value in milliseconds for receiving the entire request from the client. + See `server.requestTimeout`. + **/ + @:optional var requestTimeout:Int; + + /** + Sets the timeout value in milliseconds for receiving the complete HTTP headers from the client. + See `server.headersTimeout`. + **/ + @:optional var headersTimeout:Int; + + /** + The number of milliseconds of inactivity a server needs to wait for additional incoming data, + after it has finished writing the last response, before a socket will be destroyed. + **/ + @:optional var keepAliveTimeout:Int; + + /** + Additional milliseconds of inactivity to allow before destroying a keep-alive socket + after `keepAliveTimeout` elapses. Default: `1000`. + **/ + @:optional var keepAliveTimeoutBuffer:Int; + + /** + Sets the interval value in milliseconds to check for request and headers timeout in incomplete requests. + **/ + @:optional var connectionsCheckingInterval:Int; + + /** + Sets the maximum number of requests that may be made on a single socket before it is closed. + Default: `0` (no limit). + **/ + @:optional var maxRequestsPerSocket:Int; + + /** + Whether or not to enable keep-alive on incoming connections. + **/ + @:optional var keepAlive:Bool; + + /** + Initial delay for keep-alive in milliseconds. + **/ + @:optional var keepAliveInitialDelay:Int; + + /** + Optionally overrides all `net.Socket`s' `readableHighWaterMark` and `writableHighWaterMark`. + **/ + @:optional var highWaterMark:Int; + + /** + If set to `true`, it disables the use of Nagle's algorithm immediately after a new incoming connection is received. + **/ + @:optional var noDelay:Bool; + + /** + Sets the maximum number of unique header names allowed per request. Default: `2000`. + **/ + @:optional var joinDuplicateHeaders:Bool; + + /** + `uniqueHeaders` is an optional configuration specific to HTTP servers. + + @see https://nodejs.org/api/http.html#httpcreateserveroptions-requestlistener + **/ + @:optional var uniqueHeaders:Array>>; } /** @@ -154,11 +255,7 @@ typedef HttpRequestOptions = { See [agent.createConnection()](https://nodejs.org/api/http.html#http_agent_createconnection_options_callback) for more details. Any `Duplex` stream is a valid return value. **/ - #if haxe4 @:optional var createConnection:(options:SocketConnectOptionsTcp, ?callabck:(err:Error, stream:IDuplex) -> Void) -> IDuplex; - #else - @:optional var createConnection:SocketConnectOptionsTcp->?(Error->IDuplex->Void)->IDuplex; - #end /** Default port for the protocol. @@ -242,4 +339,39 @@ typedef HttpRequestOptions = { This will set the timeout before the socket is connected. **/ @:optional var timeout:Int; + + /** + Local port to bind to for network connections. + **/ + @:optional var localPort:Int; + + /** + Optional dns.lookup() hints. + **/ + @:optional var hints:Int; + + /** + An AbortSignal that may be used to abort an ongoing request. + **/ + @:optional var signal:AbortSignal; + + /** + Headers names which values are treated as arrays of values. + **/ + @:optional var uniqueHeaders:Array>>; + + /** + Join duplicate headers into a comma-separated string for select headers. + **/ + @:optional var joinDuplicateHeaders:Bool; + + /** + Optionally overrides the value of `--max-http-header-size` for request parsing. + **/ + @:optional var maxHeaderSize:Int; + + /** + If `true`, use an insecure HTTP parser that accepts invalid HTTP headers. + **/ + @:optional var insecureHTTPParser:Bool; } diff --git a/src/js/node/Http2.hx b/src/js/node/Http2.hx new file mode 100644 index 00000000..09024e1f --- /dev/null +++ b/src/js/node/Http2.hx @@ -0,0 +1,384 @@ +/* + * Copyright (C)2014-2020 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package js.node; + +import haxe.DynamicAccess; +import haxe.extern.EitherType; +import js.node.http2.ClientHttp2Session; +import js.node.http2.Http2Constants; +import js.node.http2.Http2SecureServer; +import js.node.http2.Http2Server; +import js.node.http2.Http2ServerRequest; +import js.node.http2.Http2ServerResponse; +import js.node.http2.ServerHttp2Session; +import js.node.stream.Duplex; +import js.node.tls.SecureContext.SecureContextOptions; +import js.node.url.URL; +import js.node.web.AbortSignal; +import js.lib.Symbol; + +/** + HTTP/2 headers object. + + Header names are lower-cased. Pseudo-headers such as `:status` may be present. + Outgoing `:status` values are numeric. +**/ +typedef Http2Headers = DynamicAccess>, Int>>; + +/** + Incoming HTTP/2 headers. Values are strings or string arrays; `:status` may appear as a number on responses. +**/ +typedef IncomingHttp2Headers = DynamicAccess>, Int>>; + +/** + Settings object used by `Http2Session` instances. +**/ +typedef Http2Settings = { + @:optional var headerTableSize:Int; + @:optional var enablePush:Bool; + @:optional var initialWindowSize:Int; + @:optional var maxFrameSize:Int; + @:optional var maxConcurrentStreams:Int; + @:optional var maxHeaderListSize:Int; + @:optional var enableConnectProtocol:Bool; + @:optional var customSettings:DynamicAccess; +} + +/** + State information about an `Http2Session`. +**/ +typedef Http2SessionState = { + @:optional var effectiveLocalWindowSize:Int; + @:optional var effectiveRecvDataLength:Int; + @:optional var nextStreamID:Int; + @:optional var localWindowSize:Int; + @:optional var lastProcStreamID:Int; + @:optional var remoteWindowSize:Int; + @:optional var outboundQueueSize:Int; + @:optional var deflateDynamicTableSize:Int; + @:optional var inflateDynamicTableSize:Int; +} + +/** + State information about an `Http2Stream`. +**/ +typedef Http2StreamState = { + @:optional var localWindowSize:Int; + @:optional var state:Int; + @:optional var localClose:Int; + @:optional var remoteClose:Int; + @:deprecated("Priority signaling is no longer supported in Node.js") @:optional var sumDependencyWeight:Int; + @:deprecated("Priority signaling is no longer supported in Node.js") @:optional var weight:Int; +} + +/** + Base session options shared by client and server sessions. +**/ +typedef Http2SessionOptions = { + /** + Sets the maximum dynamic table size for deflating header fields. + Default: `4096`. + **/ + @:optional var maxDeflateDynamicTableSize:Int; + + /** + Sets the maximum number of settings entries per `SETTINGS` frame. + Default: `32`. + **/ + @:optional var maxSettings:Int; + + /** + Sets the maximum memory that the `Http2Session` is permitted to use (megabytes). + Default: `10`. + **/ + @:optional var maxSessionMemory:Int; + + /** + Sets the maximum number of header entries. + Default: `128`. + **/ + @:optional var maxHeaderListPairs:Int; + + /** + Sets the maximum number of outstanding, unacknowledged pings. + Default: `10`. + **/ + @:optional var maxOutstandingPings:Int; + + /** + Sets the maximum allowed size for a serialized, compressed block of headers. + **/ + @:optional var maxSendHeaderBlockLength:Int; + + /** + Strategy used for determining the amount of padding to use for `HEADERS` and `DATA` frames. + Default: `Http2.constants.PADDING_STRATEGY_NONE`. + **/ + @:optional var paddingStrategy:Int; + + /** + Sets the maximum number of concurrent streams for the remote peer. + Default: `100`. + **/ + @:optional var peerMaxConcurrentStreams:Int; + + /** + The initial settings to send to the remote peer upon connection. + **/ + @:optional var settings:Http2Settings; + + /** + Setting types included in the `customSettings` property of received remote settings. + **/ + @:optional var remoteCustomSettings:Array; + + /** + Timeout in milliseconds when an `'unknownProtocol'` event is emitted. + Default: `10000`. + **/ + @:optional var unknownProtocolTimeout:Int; + + /** + If `true`, turns on strict leading/trailing whitespace validation for HTTP/2 header fields. + Default: `true`. + **/ + @:optional var strictFieldWhitespaceValidation:Bool; +} + +/** + Options for `Http2.connect`. +**/ +typedef Http2ClientSessionOptions = { + > Http2SessionOptions, + + /** + Maximum number of reserved push streams the client will accept. + Default: `200`. + **/ + @:optional var maxReservedRemoteStreams:Int; + + /** + Optional callback that returns a `Duplex` stream to use as the connection. + **/ + @:optional var createConnection:(authority:URL, options:Http2SessionOptions) -> IDuplex; + + /** + The protocol to connect with if not set in the authority. + Default: `'https:'`. + **/ + @:optional var protocol:String; +} + +/** + Secure client session options (combines session and TLS connect options). +**/ +typedef Http2SecureClientSessionOptions = { + > Http2ClientSessionOptions, + > js.node.Tls.TlsConnectOptions, + > SecureContextOptions, +} + +/** + Options for HTTP/1 fallback classes used by HTTP/2 servers. +**/ +typedef Http2Http1Options = { + @:optional var IncomingMessage:Class; + @:optional var ServerResponse:Class; + @:optional var keepAliveTimeout:Int; +} + +/** + Options for `Http2.createServer`. +**/ +typedef Http2ServerOptions = { + > Http2SessionOptions, + + @:optional var maxSessionRejectedStreams:Int; + @:optional var maxSessionInvalidFrames:Int; + @:optional var streamResetBurst:Int; + @:optional var streamResetRate:Int; + + /** + Deprecated. Use `http1Options.IncomingMessage` instead. + See DEP0202. + **/ + @:deprecated("Use http1Options.IncomingMessage instead") + @:optional var Http1IncomingMessage:Class; + + /** + Deprecated. Use `http1Options.ServerResponse` instead. + See DEP0202. + **/ + @:deprecated("Use http1Options.ServerResponse instead") + @:optional var Http1ServerResponse:Class; + + /** + Options for configuring the HTTP/1 fallback when `allowHTTP1` is `true`. + Added in Node.js v24.15.0 (Active LTS); not available on Maintenance LTS 22.x. + **/ + @:optional var http1Options:Http2Http1Options; + + @:optional var Http2ServerRequest:Class; + @:optional var Http2ServerResponse:Class; + + /** + If `true`, strict validation is used for headers and trailers defined as + having only a single value. + Default: `true`. + Added in Node.js v24.15.0 (Active LTS); not available on Maintenance LTS 22.x. + **/ + @:optional var strictSingleValueFields:Bool; +} + +/** + Options for `Http2.createSecureServer`. +**/ +typedef Http2SecureServerOptions = { + > Http2ServerOptions, + > js.node.Tls.TlsCreateServerOptions, + > SecureContextOptions, + + /** + Set to `true` to enable support for HTTP/1.1 requests. + **/ + @:optional var allowHTTP1:Bool; + + /** + Origins to include in an `ORIGIN` frame. + **/ + @:optional var origins:Array; +} + +/** + Options for `ClientHttp2Session.request`. +**/ +typedef Http2ClientSessionRequestOptions = { + @:optional var endStream:Bool; + @:optional var exclusive:Bool; + @:optional var parent:Int; + @:optional var waitForTrailers:Bool; + @:optional var signal:AbortSignal; +} + +/** + Options for `ServerHttp2Stream.respond`. +**/ +typedef Http2ServerStreamResponseOptions = { + @:optional var endStream:Bool; + @:optional var waitForTrailers:Bool; +} + +/** + Options for `ServerHttp2Stream.pushStream`. +**/ +typedef Http2PushStreamOptions = { + @:optional var exclusive:Bool; + @:optional var parent:Int; + + /** + Priority signaling is deprecated (RFC 9113). Ignored with a runtime warning since Node.js v24.2.0. + **/ + @:deprecated("Priority signaling is no longer supported in Node.js") + @:optional var weight:Int; + + @:optional var silent:Bool; +} + +/** + `statCheck` options for file responses. +**/ +typedef Http2StatOptions = { + var offset:Int; + var length:Int; +} + +/** + Options for `ServerHttp2Stream.respondWithFile` / `respondWithFD`. +**/ +typedef Http2ServerStreamFileResponseOptions = { + @:optional var statCheck:(stats:js.node.fs.Stats, headers:Http2Headers, statOptions:Http2StatOptions) -> EitherType; + @:optional var waitForTrailers:Bool; + @:optional var offset:Int; + @:optional var length:Int; + @:optional var onError:(err:js.lib.Error) -> Void; +} + +/** + The `node:http2` module provides an implementation of the HTTP/2 protocol. +**/ +@:jsRequire("http2") +extern class Http2 { + /** + Constants for HTTP/2 sessions, streams, headers, methods and status codes. + **/ + static var constants(default, null):Http2Constants; + + /** + Symbol that can be set as a property on an HTTP/2 headers object with an array value + to mark headers as sensitive. + **/ + static var sensitiveHeaders(default, null):Symbol; + + /** + Returns an object containing the default settings for an `Http2Session` instance. + This method returns a new object instance every time it is called. + **/ + static function getDefaultSettings():Http2Settings; + + /** + Returns a `Buffer` containing the serialized representation of the given HTTP/2 settings. + **/ + static function getPackedSettings(settings:Http2Settings):Buffer; + + /** + Returns an HTTP/2 settings object containing the deserialized settings from the given buffer. + **/ + static function getUnpackedSettings(buf:Buffer):Http2Settings; + + /** + Returns a `net.Server` instance that creates and manages `Http2Session` instances. + **/ + @:overload(function(options:Http2ServerOptions, ?onRequestHandler:(request:Http2ServerRequest, response:Http2ServerResponse) -> Void):Http2Server {}) + static function createServer(?onRequestHandler:(request:Http2ServerRequest, response:Http2ServerResponse) -> Void):Http2Server; + + /** + Returns a `tls.Server` instance that creates and manages `Http2Session` instances. + **/ + @:overload(function(options:Http2SecureServerOptions, ?onRequestHandler:(request:Http2ServerRequest, response:Http2ServerResponse) -> Void):Http2SecureServer {}) + static function createSecureServer(?onRequestHandler:(request:Http2ServerRequest, response:Http2ServerResponse) -> Void):Http2SecureServer; + + /** + Returns a `ClientHttp2Session` instance. + **/ + @:overload(function(authority:URL, listener:(session:ClientHttp2Session, socket:js.node.net.Socket) -> Void):ClientHttp2Session {}) + @:overload(function(authority:String, listener:(session:ClientHttp2Session, socket:js.node.net.Socket) -> Void):ClientHttp2Session {}) + @:overload(function(authority:URL, ?options:EitherType, + ?listener:(session:ClientHttp2Session, socket:js.node.net.Socket) -> Void):ClientHttp2Session {}) + static function connect(authority:String, ?options:EitherType, + ?listener:(session:ClientHttp2Session, socket:js.node.net.Socket) -> Void):ClientHttp2Session; + + /** + Create an HTTP/2 server session from an existing duplex socket. + **/ + static function performServerHandshake(socket:IDuplex, ?options:Http2ServerOptions):ServerHttp2Session; +} diff --git a/src/js/node/Https.hx b/src/js/node/Https.hx index 62af3384..c321f257 100644 --- a/src/js/node/Https.hx +++ b/src/js/node/Https.hx @@ -37,13 +37,8 @@ extern class Https { /** Returns a new HTTPS web server object. **/ - #if haxe4 @:overload(function(options:HttpsCreateServerOptions, ?requestListener:(request:IncomingMessage, response:ServerResponse) -> Void):Server {}) static function createServer(?requestListener:(request:IncomingMessage, response:ServerResponse) -> Void):Server; - #else - @:overload(function(options:HttpsCreateServerOptions, ?requestListener:IncomingMessage->ServerResponse->Void):Server {}) - static function createServer(?requestListener:IncomingMessage->ServerResponse->Void):Server; - #end /** Like `Http.get` but for HTTPS. @@ -90,5 +85,4 @@ typedef HttpsCreateServerOptions = { typedef HttpsRequestOptions = { > js.node.Http.HttpRequestOptions, > js.node.Tls.TlsConnectOptions, - // TODO: clean those options up } diff --git a/src/js/node/Inspector.hx b/src/js/node/Inspector.hx new file mode 100644 index 00000000..00de4e80 --- /dev/null +++ b/src/js/node/Inspector.hx @@ -0,0 +1,76 @@ +/* + * Copyright (C)2014-2020 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package js.node; + +import js.node.inspector.InspectorConsole; + +/** + The `inspector` module provides an API for interacting with the V8 inspector. + + Related types live under `js.node.inspector` (`Session`, `Network`, `NetworkResources`, `DomStorage`). + Use those types directly (e.g. `js.node.inspector.Network.requestWillBeSent(...)`) — they map to + `inspector.Network` / `inspector.NetworkResources` / `inspector.DOMStorage` via `@:jsRequire`. + + @see https://nodejs.org/docs/latest-v24.x/api/inspector.html +**/ +@:jsRequire("inspector") +extern class Inspector { + /** + Activate inspector on host and port. Equivalent to `node --inspect=[[host:]port]`, + but can be done programmatically after node has started. + + If `wait` is `true`, will block until a client has connected to the inspect port + and flow control has been passed to the debugger client. + + Returns a Disposable (`{ [Symbol.dispose](): void }`) that calls `inspector.close()`. + + // TODO: model Web IDL `Disposable` / `Symbol.dispose` instead of `Dynamic`. + **/ + static function open(?port:Int, ?host:String, ?wait:Bool):Dynamic; + + /** + Attempts to close all remaining connections, blocking the event loop until all are closed. + Once all connections are closed, deactivates the inspector. + **/ + static function close():Void; + + /** + Return the URL of the active inspector, or `undefined` if there is none. + **/ + static function url():Null; + + /** + Blocks until a client (existing or connected later) has sent + `Runtime.runIfWaitingForDebugger` command. + + An exception will be thrown if there is no active inspector. + **/ + static function waitForDebugger():Void; + + /** + An object to send messages to the remote inspector console. + + The inspector console does not have API parity with Node.js console. + **/ + static var console(default, null):InspectorConsole; +} diff --git a/src/js/node/InspectorPromises.hx b/src/js/node/InspectorPromises.hx new file mode 100644 index 00000000..48fe1d34 --- /dev/null +++ b/src/js/node/InspectorPromises.hx @@ -0,0 +1,69 @@ +/* + * Copyright (C)2014-2020 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package js.node; + +import js.node.inspector.InspectorConsole; +import js.node.inspector.promises.Session; + +/** + Promise-based `inspector` API (`inspector/promises`). + + Stability: 1 - Experimental. + + Module-level helpers match `Inspector`; use `js.node.inspector.promises.Session` + for a `Session` whose `post` returns a `Promise`. DevTools helpers live under + `js.node.inspector` (`Network`, `NetworkResources`, `DomStorage`). + + @see https://nodejs.org/docs/latest-v24.x/api/inspector.html#promises-api +**/ +@:jsRequire("inspector/promises") +extern class InspectorPromises { + /** + Activate inspector on host and port. + + Returns a Disposable (`{ [Symbol.dispose](): void }`) that calls `close()`. + + // TODO: model Web IDL `Disposable` / `Symbol.dispose` instead of `Dynamic`. + **/ + static function open(?port:Int, ?host:String, ?wait:Bool):Dynamic; + + /** + Attempts to close all remaining connections, blocking the event loop until all are closed. + **/ + static function close():Void; + + /** + Return the URL of the active inspector, or `undefined` if there is none. + **/ + static function url():Null; + + /** + Blocks until a client has sent `Runtime.runIfWaitingForDebugger`. + **/ + static function waitForDebugger():Void; + + /** + An object to send messages to the remote inspector console. + **/ + static var console(default, null):InspectorConsole; +} diff --git a/src/js/node/Iterator.hx b/src/js/node/Iterator.hx index d1f4d482..775583fb 100644 --- a/src/js/node/Iterator.hx +++ b/src/js/node/Iterator.hx @@ -1,37 +1,26 @@ -/* - * Copyright (C)2014-2020 Haxe Foundation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package js.node; - -#if haxe4 -typedef Iterator = js.lib.Iterator; -typedef IteratorStep = js.lib.Iterator.IteratorStep; -#else -typedef Iterator = { - function next():IteratorStep; -} - -typedef IteratorStep = { - done:Bool, - ?value:T -} -#end +/* + * Copyright (C)2014-2020 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package js.node; + +typedef Iterator = js.lib.Iterator; +typedef IteratorStep = js.lib.Iterator.IteratorStep; diff --git a/src/js/node/Module.hx b/src/js/node/Module.hx index 1cb43429..061c212e 100644 --- a/src/js/node/Module.hx +++ b/src/js/node/Module.hx @@ -22,6 +22,9 @@ package js.node; +import haxe.Constraints.Function; +import haxe.extern.EitherType; +import js.node.module.SourceMap; import js.node.url.URL; /** @@ -42,67 +45,61 @@ extern class Module { /** The `module.exports` object is created by the Module system. - Sometimes this is not acceptable; many want their module to be an instance of some class. - To do this, assign the desired export object to `module.exports`. - Assigning the desired object to `exports` will simply rebind the local `exports` variable, which is probably not - what is desired. - - @see https://nodejs.org/api/modules.html#modules_module_exports **/ var exports:Dynamic; /** The fully resolved filename of the module. - - @see https://nodejs.org/api/modules.html#modules_module_filename **/ var filename(default, null):String; /** The identifier for the module. Typically this is the fully resolved filename. - - @see https://nodejs.org/api/modules.html#modules_module_id **/ var id(default, null):String; /** Whether or not the module is done loading, or is in the process of loading. - - @see https://nodejs.org/api/modules.html#modules_module_loaded **/ var loaded(default, null):Bool; /** The module that first required this one. - - @see https://nodejs.org/api/modules.html#modules_module_parent **/ var parent(default, null):Module; /** The search paths for the module. - - @see https://nodejs.org/api/modules.html#modules_module_paths **/ var paths(default, null):Array; + /** + True if the module is running during the Node.js bootstrap process. + **/ + var isPreloading(default, null):Bool; + + /** + The directory name of the module. + **/ + var path(default, null):String; + /** The `module.require()` method provides a way to load a module as if `require()` was called from the original module. - - @see https://nodejs.org/api/modules.html#modules_module_require_id **/ function require(id:String):Dynamic; /** A list of the names of all modules provided by Node.js. - Can be used to verify if a module is maintained by a third party or not. - - @see https://nodejs.org/api/modules.html#modules_module_builtinmodules **/ static var builtinModules(default, null):Array; + /** + Returns `true` if the module is a core/built-in module. + **/ + static function isBuiltin(moduleName:String):Bool; + /** @see https://nodejs.org/api/modules.html#modules_module_createrequire_filename **/ @@ -112,9 +109,175 @@ extern class Module { /** The `module.syncBuiltinESMExports()` method updates all the live bindings for builtin ES Modules to match the properties of the CommonJS exports. - It does not add or remove exported names from the ES Modules. - - @see https://nodejs.org/api/modules.html#modules_module_syncbuiltinesmexports **/ static function syncBuiltinESMExports():Void; + + /** + `findSourceMap` finds the corresponding source map for a given file path. + + @see https://nodejs.org/api/module.html#modulefindsourcemappath + **/ + static function findSourceMap(path:String):Null; + + /** + Removes TypeScript type annotations from `code`. + **/ + static function stripTypeScriptTypes(code:String, ?options:ModuleStripTypeScriptTypesOptions):String; + + /** + Register synchronous customization hooks. + + Hook callback signatures stay loosely typed (`Function`); full + `resolve`/`load` context models can be refined later. + + @see https://nodejs.org/api/module.html#moduleregisterhooksoptions + **/ + static function registerHooks(options:ModuleRegisterHooksOptions):ModuleHooks; + + /** + Finds the closest `package.json` for the given specifier. + + @see https://nodejs.org/api/module.html#modulefindpackagejsonspecifier-base + **/ + @:overload(function(specifier:URL, ?base:EitherType):Null {}) + static function findPackageJSON(specifier:String, ?base:EitherType):Null; + + /** + Register a module that exports hooks that customize Node.js module resolution and loading. + + @see https://nodejs.org/api/module.html#moduleregisterspecifier-parenturl-options + **/ + @:overload(function(specifier:String, parentURL:EitherType, ?options:ModuleRegisterOptions):Void {}) + @:overload(function(specifier:URL, parentURL:EitherType, ?options:ModuleRegisterOptions):Void {}) + @:overload(function(specifier:URL, ?options:ModuleRegisterOptions):Void {}) + static function register(specifier:String, ?options:ModuleRegisterOptions):Void; + + /** + Enable the module compile cache. + + @see https://nodejs.org/api/module.html#moduleenablecompilecachecachedir + **/ + static function enableCompileCache(?cacheDir:String):Dynamic; + + /** + Flush the module compile cache to disk. + **/ + static function flushCompileCache():Void; + + /** + Return the directory where the module compile cache is stored, if enabled. + **/ + static function getCompileCacheDir():Null; + + /** + Enable or disable Source Map v3 support for stack traces. + **/ + static function setSourceMapsSupport(enabled:Bool, ?options:ModuleSetSourceMapsSupportOptions):Void; + + /** + Return whether Source Map support is enabled and related options. + **/ + static function getSourceMapsSupport():ModuleSourceMapsSupport; +} + +/** + Options for `Module.stripTypeScriptTypes`. +**/ +typedef ModuleStripTypeScriptTypesOptions = { + /** + Mode of stripping. Default: `'strip'`. + **/ + @:optional var mode:String; + + /** + Whether to produce source maps. Default: `false`. + **/ + @:optional var sourceMap:Bool; + + /** + The filename used when generating source maps. + **/ + @:optional var sourceUrl:String; +} + +/** + Options for `Module.register`. +**/ +typedef ModuleRegisterOptions = { + /** + Base URL used to resolve relative `specifier` values when `parentURL` is not + passed as a separate argument. Default: `'data:'`. + **/ + @:optional var parentURL:EitherType; + + /** + Arbitrary cloneable value passed into the initialize hook. + **/ + @:optional var data:Dynamic; + + /** + Transferable objects passed into the initialize hook. + // TODO(section-5): tighten once worker_threads transferable typing is settled. + **/ + @:optional var transferList:Array; +} + +/** + Options for `Module.registerHooks`. +**/ +typedef ModuleRegisterHooksOptions = { + /** + Synchronous load hook. See Node.js module customization hooks. + **/ + @:optional var load:Function; + + /** + Synchronous resolve hook. See Node.js module customization hooks. + **/ + @:optional var resolve:Function; +} + +/** + Handle returned by `Module.registerHooks`. +**/ +typedef ModuleHooks = { + /** + Deregister the hook instance. + **/ + function deregister():Void; +} + +/** + Options for `Module.setSourceMapsSupport`. +**/ +typedef ModuleSetSourceMapsSupportOptions = { + /** + Enable support for files in `node_modules`. Default: `false`. + **/ + @:optional var nodeModules:Bool; + + /** + Enable support for generated code from `eval` / `new Function`. Default: `false`. + **/ + @:optional var generatedCode:Bool; +} + +/** + Result of `Module.getSourceMapsSupport`. +**/ +typedef ModuleSourceMapsSupport = { + /** + Whether Source Map v3 support is enabled. + **/ + var enabled:Bool; + + /** + Whether support is enabled for files in `node_modules`. + **/ + var nodeModules:Bool; + + /** + Whether support is enabled for generated code from `eval` / `new Function`. + **/ + var generatedCode:Bool; } diff --git a/src/js/node/Net.hx b/src/js/node/Net.hx index dc011b82..424677f4 100644 --- a/src/js/node/Net.hx +++ b/src/js/node/Net.hx @@ -23,8 +23,10 @@ package js.node; import haxe.extern.EitherType; +import js.node.net.BlockList as BlockListObject; import js.node.net.Server; import js.node.net.Socket; +import js.node.net.SocketAddress as SocketAddressObject; typedef NetCreateServerOptions = { > SocketOptionsBase, @@ -39,6 +41,31 @@ typedef NetCreateServerOptions = { Default: false **/ @:optional var pauseOnConnect:Bool; + + /** + If set to `true`, it enables keep-alive functionality on the socket immediately after the connection is established. + **/ + @:optional var keepAlive:Bool; + + /** + If set to a positive number, it sets the initial delay before the first keepalive probe is sent on an idle socket. + **/ + @:optional var keepAliveInitialDelay:Int; + + /** + If set to `true`, it disables the use of Nagle's algorithm immediately after a connection is established. + **/ + @:optional var noDelay:Bool; + + /** + Optionally overrides all `net.Socket`s' `readableHighWaterMark` and `writableHighWaterMark`. + **/ + @:optional var highWaterMark:Int; + + /** + `net.BlockList` used as an IP allow/deny list for incoming connections. + **/ + @:optional var blockList:BlockListObject; } /** @@ -122,4 +149,46 @@ extern class Net { Returns true if input is a version 6 IP address, otherwise returns false. **/ static function isIPv6(input:String):Bool; + + /** + `BlockList` class constructor. + + @see https://nodejs.org/api/net.html#class-netblocklist + **/ + static var BlockList:Class; + + /** + `SocketAddress` class constructor. + + @see https://nodejs.org/api/net.html#class-netsocketaddress + **/ + static var SocketAddress:Class; + + /** + Gets the current default value of the `autoSelectFamily` option of `socket.connect(options)`. + + @see https://nodejs.org/api/net.html#netgetdefaultautoselectfamily + **/ + static function getDefaultAutoSelectFamily():Bool; + + /** + Sets the default value of the `autoSelectFamily` option of `socket.connect(options)`. + + @see https://nodejs.org/api/net.html#netsetdefaultautoselectfamilyvalue + **/ + static function setDefaultAutoSelectFamily(value:Bool):Void; + + /** + Gets the current default value of the `autoSelectFamilyAttemptTimeout` option of `socket.connect(options)`. + + @see https://nodejs.org/api/net.html#netgetdefaultautoselectfamilyattempttimeout + **/ + static function getDefaultAutoSelectFamilyAttemptTimeout():Int; + + /** + Sets the default value of the `autoSelectFamilyAttemptTimeout` option of `socket.connect(options)`. + + @see https://nodejs.org/api/net.html#netsetdefaultautoselectfamilyattempttimeoutvalue + **/ + static function setDefaultAutoSelectFamilyAttemptTimeout(ms:Int):Void; } diff --git a/src/js/node/Os.hx b/src/js/node/Os.hx index c94b9941..706949f3 100644 --- a/src/js/node/Os.hx +++ b/src/js/node/Os.hx @@ -45,6 +45,14 @@ extern class Os { **/ static function arch():String; + /** + Returns an estimate of the default amount of parallelism a program should use. + Always returns a value greater than zero. + + @see https://nodejs.org/api/os.html#osavailableparallelism + **/ + static function availableParallelism():Int; + /** Returns an object containing commonly used operating system specific constants for error codes, process signals, and so on. The specific constants currently defined are described in OS Constants. @@ -59,6 +67,14 @@ extern class Os { **/ static function cpus():Array; + /** + The platform-specific file path of the null device. + `'\\.\nul'` on Windows and `'/dev/null'` on POSIX. + + @see https://nodejs.org/api/os.html#osdevnull + **/ + static var devNull(default, null):String; + /** The `os.endianness()` method returns a string identifying the endianness of the CPU for which the Node.js binary was compiled. @@ -101,6 +117,13 @@ extern class Os { **/ static function loadavg():Array; + /** + Returns the machine type as a string, such as `arm`, `arm64`, `aarch64`, `mips`, `mips64`, `ppc64`, `ppc64le`, `s390x`, `i386`, `i686`, `x86_64`. + + @see https://nodejs.org/api/os.html#osmachine + **/ + static function machine():String; + /** The `os.networkInterfaces()` method returns an object containing only network interfaces that have been assigned a network address. @@ -163,6 +186,15 @@ extern class Os { @see https://nodejs.org/api/os.html#os_os_userinfo_options **/ static function userInfo(?options:{encoding:String}):OsUserInfo; + + /** + Returns a string identifying the kernel version. + + On POSIX systems, the operating system release is determined by calling uname(3). On Windows, `RtlGetVersion()` is used, and if it is not available, `GetVersionExW()` will be used. + + @see https://nodejs.org/api/os.html#osversion + **/ + static function version():String; } /** diff --git a/src/js/node/Path.hx b/src/js/node/Path.hx index f52390fc..9a86a848 100644 --- a/src/js/node/Path.hx +++ b/src/js/node/Path.hx @@ -82,6 +82,13 @@ extern class Path { **/ static function join(paths:haxe.extern.Rest):String; + /** + The `path.matchesGlob()` method determines if `path` matches the `pattern`. + + @see https://nodejs.org/api/path.html#pathmatchesglobpath-pattern + **/ + static function matchesGlob(path:String, pattern:String):Bool; + /** The `path.normalize()` method normalizes the given `path`, resolving `'..'` and `'.'` segments. @@ -189,8 +196,10 @@ private typedef PathModule = { function dirname(path:String):String; function basename(path:String, ?ext:String):String; function extname(path:String):String; + function matchesGlob(path:String, pattern:String):Bool; var sep(default, null):String; var delimiter(default, null):String; function parse(pathString:String):PathObject; function format(pathObject:PathObject):String; + function toNamespacedPath(path:String):String; } diff --git a/src/js/node/PerfHooks.hx b/src/js/node/PerfHooks.hx new file mode 100644 index 00000000..b8dcef6f --- /dev/null +++ b/src/js/node/PerfHooks.hx @@ -0,0 +1,174 @@ +/* + * Copyright (C)2014-2020 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package js.node; + +import haxe.Constraints.Function; +import haxe.extern.EitherType; +import js.node.perf_hooks.IntervalHistogram; +import js.node.perf_hooks.Performance; +import js.node.perf_hooks.RecordableHistogram; + +/** + This module provides an implementation of a subset of the W3C Web Performance APIs + as well as additional APIs for Node.js-specific performance measurements. + + @see https://nodejs.org/docs/latest-v24.x/api/perf_hooks.html +**/ +@:jsRequire("perf_hooks") +extern class PerfHooks { + /** + An object that can be used to collect performance metrics from the current Node.js instance. + It is similar to `window.performance` in browsers. + + Also available as `js.Node.performance`. + + @see https://nodejs.org/docs/latest-v24.x/api/perf_hooks.html#perf_hooksperformance + **/ + static var performance(default, never):Performance; + + /** + Constants for garbage collection kinds and flags. + + @see https://nodejs.org/docs/latest-v24.x/api/perf_hooks.html#perf_hooksconstants + **/ + static var constants(default, never):PerfHooksConstants; + + /** + Returns a `RecordableHistogram`. + + @see https://nodejs.org/api/perf_hooks.html#perf_hookscreatehistogramoptions + **/ + static function createHistogram(?options:CreateHistogramOptions):RecordableHistogram; + + /** + Creates an `IntervalHistogram` object that samples and reports the event loop delay over time. + The delays will be reported in nanoseconds. + + This property is an extension by Node.js. It is not available in Web browsers. + + @see https://nodejs.org/api/perf_hooks.html#perf_hooksmonitoreventloopdelayoptions + **/ + static function monitorEventLoopDelay(?options:EventLoopMonitorOptions):IntervalHistogram; + + /** + Returns an object that contains the cumulative duration of time the event loop has been + both idle and active as a high resolution milliseconds timer. + + Module-level alias of `performance.eventLoopUtilization()`. + Added in Node.js v24.12.0 (Active LTS). On earlier versions (including Node.js 22 LTS) + this is `undefined` at module level; use `PerfHooks.performance.eventLoopUtilization` instead. + + @see https://nodejs.org/api/perf_hooks.html#perf_hookseventlooputilizationutilization1-utilization2 + **/ + static function eventLoopUtilization(?utilization1:EventLoopUtilization, ?utilization2:EventLoopUtilization):EventLoopUtilization; + + /** + Wraps a function within a new function that measures the running time of the wrapped function. + A `PerformanceObserver` must be subscribed to the `'function'` event type in order for the + timing details to be accessed. + + This property is an extension by Node.js. It is not available in Web browsers. + + Module-level alias of `performance.timerify()`. + Added in Node.js v24.12.0 (Active LTS). On earlier versions (including Node.js 22 LTS) + this is `undefined` at module level; use `PerfHooks.performance.timerify` instead. + + @see https://nodejs.org/api/perf_hooks.html#perf_hookstimerifyfn-options + **/ + static function timerify(fn:T, ?options:TimerifyOptions):T; +} + +/** + Constants exported by `perf_hooks.constants`. +**/ +typedef PerfHooksConstants = { + var NODE_PERFORMANCE_GC_MAJOR(default, never):Int; + var NODE_PERFORMANCE_GC_MINOR(default, never):Int; + var NODE_PERFORMANCE_GC_INCREMENTAL(default, never):Int; + var NODE_PERFORMANCE_GC_WEAKCB(default, never):Int; + var NODE_PERFORMANCE_GC_FLAGS_NO(default, never):Int; + var NODE_PERFORMANCE_GC_FLAGS_CONSTRUCT_RETAINED(default, never):Int; + var NODE_PERFORMANCE_GC_FLAGS_FORCED(default, never):Int; + var NODE_PERFORMANCE_GC_FLAGS_SYNCHRONOUS_PHANTOM_PROCESSING(default, never):Int; + var NODE_PERFORMANCE_GC_FLAGS_ALL_AVAILABLE_GARBAGE(default, never):Int; + var NODE_PERFORMANCE_GC_FLAGS_ALL_EXTERNAL_MEMORY(default, never):Int; + var NODE_PERFORMANCE_GC_FLAGS_SCHEDULE_IDLE(default, never):Int; +} + +/** + Options for `PerfHooks.createHistogram`. +**/ +typedef CreateHistogramOptions = { + /** + The lowest discernible value. Must be an integer value greater than 0. + Default: `1`. + + // TODO: allow BigInt when hxnodejs gains a BigInt type (Node accepts number | bigint). + **/ + @:optional var lowest:EitherType; + + /** + The highest recordable value. Must be an integer value that is equal to or greater than + two times `lowest`. Default: `Number.MAX_SAFE_INTEGER`. + + // TODO: allow BigInt when hxnodejs gains a BigInt type (Node accepts number | bigint). + **/ + @:optional var highest:EitherType; + + /** + The number of accuracy digits. Must be a number between `1` and `5`. + Default: `3`. + **/ + @:optional var figures:Int; +} + +/** + Options for `PerfHooks.monitorEventLoopDelay`. +**/ +typedef EventLoopMonitorOptions = { + /** + The sampling rate in milliseconds. Must be greater than zero. + Default: `10`. + **/ + @:optional var resolution:Float; +} + +/** + Result of `PerfHooks.eventLoopUtilization` / `Performance.eventLoopUtilization`. +**/ +typedef EventLoopUtilization = { + var idle:Float; + var active:Float; + var utilization:Float; +} + +/** + Options for `PerfHooks.timerify` / `Performance.timerify`. +**/ +typedef TimerifyOptions = { + /** + A histogram object created using `PerfHooks.createHistogram()` that will record + runtime durations in nanoseconds. + **/ + @:optional var histogram:RecordableHistogram; +} diff --git a/src/js/node/Process.hx b/src/js/node/Process.hx index c59f9d65..532307ef 100644 --- a/src/js/node/Process.hx +++ b/src/js/node/Process.hx @@ -23,17 +23,18 @@ package js.node; import haxe.DynamicAccess; +import haxe.Constraints.Function; import haxe.extern.EitherType; import haxe.extern.Rest; +import js.lib.Error; +import js.node.child_process.ChildProcess.ChildProcessChannel; +import js.node.child_process.ChildProcess.ChildProcessSendHandle; import js.node.child_process.ChildProcess.ChildProcessSendOptions; import js.node.events.EventEmitter; -import js.node.stream.Readable; -import js.node.stream.Writable; -#if haxe4 -import js.lib.Error; -#else -import js.Error; -#end +import js.node.process.ProcessFinalization; +import js.node.process.ProcessPermission; +import js.node.stream.Readable.IReadable; +import js.node.stream.Writable.IWritable; /** Enumeration of events emitted by the Process class. @@ -50,14 +51,7 @@ enum abstract ProcessEvent(Event) to Event { var Exit:ProcessEventVoid> = "exit"; /** - Emitted when node empties it's event loop and has nothing else to schedule. - - Normally, node exits when there is no work scheduled, but a listener for `beforeExit` - can make asynchronous calls, and cause node to continue. - - `beforeExit` is not emitted for conditions causing explicit termination, such as `process.exit()` - or uncaught exceptions, and should not be used as an alternative to the `exit` event - unless the intention is to schedule more work. + Emitted when node empties its event loop and has nothing else to schedule. **/ var BeforeExit:ProcessEventVoid> = "beforeExit"; @@ -67,20 +61,47 @@ enum abstract ProcessEvent(Event) to Event { will not occur. **/ var UncaughtException:ProcessEventVoid> = "uncaughtException"; + + /** + This event is emitted before an `'uncaughtException'` event is emitted or a hook installed via + `process.setUncaughtExceptionCaptureCallback()` is called. + **/ + var UncaughtExceptionMonitor:ProcessEventVoid> = "uncaughtExceptionMonitor"; + + /** + Emitted whenever a `Promise` is rejected and no error handler is attached to the promise within a turn of the event loop. + **/ + var UnhandledRejection:ProcessEvent<(reason:Dynamic, promise:js.lib.Promise) -> Void> = "unhandledRejection"; + + /** + Emitted whenever a `Promise` has been rejected and an error handler was attached to it later than after an event loop turn. + **/ + var RejectionHandled:ProcessEvent<(promise:js.lib.Promise) -> Void> = "rejectionHandled"; + + /** + The `process` object emits a `'warning'` event whenever Node.js emits a process warning. + **/ + var Warning:ProcessEvent<(warning:Error) -> Void> = "warning"; + + /** + Emitted when a message is received over IPC. Available for child processes. + **/ + var Message:ProcessEvent<(message:Dynamic, sendHandle:Null) -> Void> = "message"; + + /** + Emitted after calling `process.disconnect()` in a child process. + **/ + var Disconnect:ProcessEventVoid> = "disconnect"; } extern class Process extends EventEmitter { /** A Writable Stream to stdout. - - `stderr` and `stdout` are unlike other streams in Node in that writes to them are usually blocking. **/ var stdout:IWritable; /** A writable stream to stderr. - - `stderr` and `stdout` are unlike other streams in Node in that writes to them are usually blocking. **/ var stderr:IWritable; @@ -91,19 +112,15 @@ extern class Process extends EventEmitter { /** An array containing the command line arguments. - The first element will be `node`, the second element will be the name of the JavaScript file. - The next elements will be any additional command line arguments. - - E.g: - $ node process-2.js one two=three four - 0: node - 1: /Users/mjr/work/node/process-2.js - 2: one - 3: two=three - 4: four **/ var argv:Array; + /** + The `process.argv0` property stores a read-only copy of the original value of `argv[0]` + passed when Node.js starts. + **/ + var argv0(default, null):String; + /** This is the absolute pathname of the executable that started the process. **/ @@ -111,13 +128,14 @@ extern class Process extends EventEmitter { /** This is the set of node-specific command line options from the executable that started the process. - These options do not show up in `argv`, and do not include the node executable, the name of the script, - or any options following the script name. - - These options are useful in order to spawn child processes with the same execution environment as the parent. **/ var execArgv:Array; + /** + If the Node.js process is spawned with an IPC channel, `process.connected` is `true` while connected. + **/ + var connected(default, null):Bool; + /** This causes node to emit an abort. This will cause node to exit and generate a core file. **/ @@ -147,8 +165,6 @@ extern class Process extends EventEmitter { /** A number which will be the process exit code, when the process either exits gracefully, or is exited via `process.exit()` without specifying a code. - - Specifying a code to `process.exit(code)` will override any previous setting of `process.exitCode`. **/ var exitCode:Null; @@ -160,51 +176,55 @@ extern class Process extends EventEmitter { /** Sets the group identity of the process. See setgid(2). - This accepts either a numerical ID or a groupname string. - If a groupname is specified, this method blocks while resolving it to a numerical ID. - - Note: this function is only available on POSIX platforms (i.e. not Windows) **/ @:overload(function(id:String):Void {}) function setgid(id:Int):Void; /** Gets the user identity of the process. See getuid(2). - Note: this function is only available on POSIX platforms (i.e. not Windows) **/ function getuid():Int; /** Sets the user identity of the process. See setuid(2). - This accepts either a numerical ID or a username string. - If a username is specified, this method blocks while resolving it to a numerical ID. - - Note: this function is only available on POSIX platforms (i.e. not Windows) **/ @:overload(function(id:String):Void {}) function setuid(id:Int):Void; + /** + Gets the effective group identity of the process. See getegid(2). + **/ + function getegid():Int; + + /** + Sets the effective group identity of the process. See setegid(2). + **/ + @:overload(function(id:String):Void {}) + function setegid(id:Int):Void; + + /** + Gets the effective user identity of the process. See geteuid(2). + **/ + function geteuid():Int; + + /** + Sets the effective user identity of the process. See seteuid(2). + **/ + @:overload(function(id:String):Void {}) + function seteuid(id:Int):Void; + /** Returns an array with the supplementary group IDs. - POSIX leaves it unspecified if the effective group ID is included but node.js ensures it always is. - Note: this function is only available on POSIX platforms (i.e. not Windows) **/ function getgroups():Array; /** Sets the supplementary group IDs. - This is a privileged operation, meaning you need to be root or have the CAP_SETGID capability. - - Note: this function is only available on POSIX platforms (i.e. not Windows) - The list can contain group IDs, group names or both. **/ function setgroups(groups:Array>):Void; /** - Reads /etc/group and initializes the group access list, using all groups of which the user is a member. - This is a privileged operation, meaning you need to be root or have the CAP_SETGID capability. - - Note: this function is only available on POSIX platforms (i.e. not Windows) + Reads /etc/group and initializes the group access list. **/ function initgroups(user:EitherType, extra_group:EitherType):Void; @@ -220,23 +240,23 @@ extern class Process extends EventEmitter { /** An Object containing the JavaScript representation of the configure options that were used to compile the current node executable. - This is the same as the "config.gypi" file that was produced when running the ./configure script. **/ - var config:Dynamic; + var config:DynamicAccess; /** - Send a signal to a process. - `pid` is the process id and `signal` is the string describing the signal to send. Signal names are strings like 'SIGINT' or 'SIGHUP'. - - If omitted, the `signal` will be 'SIGTERM'. See Signal Events and kill(2) for more information. + IPC channel reference for the process, if present. + **/ + var channel(default, null):Null; - Will throw an error if target does not exist, and as a special case, - a signal of 0 can be used to test for the existence of a process. + /** + The debugger port of the Node.js process. + **/ + var debugPort:Int; - Note that just because the name of this function is `kill`, it is really just a signal sender, like the kill system call. - The signal sent may do something other than kill the target process. + /** + Send a signal to a process. **/ - function kill(pid:Int, ?signal:String):Void; + function kill(pid:Int, ?signal:EitherType):Bool; /** The PID of the process. @@ -245,10 +265,6 @@ extern class Process extends EventEmitter { /** Getter/setter to set what is displayed in 'ps'. - - When used as a setter, the maximum length is platform-specific and probably short. - On Linux and OS X, it's limited to the size of the binary name plus the length of the - command line arguments because it overwrites the argv memory. **/ var title:String; @@ -277,25 +293,92 @@ extern class Process extends EventEmitter { **/ var report:Report; + /** + Permission model API when the process is started with `--permission`. + `null` / unavailable when the permission model is not enabled. + **/ + var permission(default, null):Null; + + /** + Provides APIs for registering callbacks invoked during process finalization. + **/ + var finalization(default, null):ProcessFinalization; + + /** + A boolean reflecting whether the current Node.js process is running with `--pending-deprecation` enabled. + **/ + var noDeprecation:Bool; + + /** + Enable logging of deprecation warnings. + **/ + var traceDeprecation:Bool; + + /** + Throw on deprecated API usage. + **/ + var throwDeprecation:Bool; + + /** + A boolean value that indicates whether source maps are enabled for Node stacks. + **/ + var sourceMapsEnabled(default, null):Bool; + + /** + A set of flags from `NODE_OPTIONS` and command-line that Node.js allows. + **/ + var allowedNodeEnvironmentFlags(default, null):js.lib.Set; + + /** + Provides a way to get available features known at compile/runtime. + **/ + var features(default, null):ProcessFeatures; + /** Returns an object describing the memory usage of the Node process measured in bytes. **/ function memoryUsage():MemoryUsage; /** - On the next loop around the event loop call this callback. - This is not a simple alias to setTimeout(fn, 0), it's much more efficient. - It typically runs before any other I/O events fire, but there are some exceptions. + Returns the resident set size (RSS) used by the process in bytes. + **/ + @:native("memoryUsage.rss") + function memoryUsageRss():Float; + + /** + Returns information about the V8 heap spaces and usage of process resources. + **/ + function resourceUsage():ResourceUsage; + + /** + Returns the user and system CPU time usage of the current process, in microseconds. + **/ + function cpuUsage(?previousValue:CpuUsage):CpuUsage; - This is important in developing APIs where you want to give the user the chance to - assign event handlers after an object has been constructed, but before any I/O has occurred. + /** + Gets the amount of free memory that is still available to the process, in bytes. + May return `undefined`/`0` if not supported. + **/ + function availableMemory():Float; + + /** + Gets the amount of memory available to the process (based on cgroup / ulimit etc.). + May return `undefined` if not constrained. + **/ + function constrainedMemory():Float; + + /** + Returns an array of strings naming active resources currently keeping the event loop alive. + **/ + function getActiveResourcesInfo():Array; + + /** + On the next loop around the event loop call this callback. **/ function nextTick(callback:Void->Void, args:Rest):Void; /** Sets or reads the process's file mode creation mask. - Child processes inherit the mask from the parent process. - Returns the old mask if mask argument is given, otherwise returns the current mask. **/ function umask(?mask:Int):Int; @@ -305,64 +388,116 @@ extern class Process extends EventEmitter { function uptime():Float; /** - Returns the current high-resolution real time in a [seconds, nanoseconds] tuple Array. - It is relative to an arbitrary time in the past. - It is not related to the time of day and therefore not subject to clock drift. - The primary use is for measuring performance between intervals. - You may pass in the result of a previous call to `hrtime` to get a diff reading, - useful for benchmarks and measuring intervals + Returns the current high-resolution real time in a `[seconds, nanoseconds]` tuple Array. **/ @:overload(function(prev:Array):Array {}) function hrtime():Array; /** - Alternate way to retrieve require.main. The difference is that if the main module changes at runtime, - require.main might still refer to the original main module in modules that were required - before the change occurred. Generally it's safe to assume that the two refer to the same module. + The `bigint` version of `process.hrtime()` that returns nanoseconds as a `bigint`. + Typed as `Dynamic` for Haxe 4.0.5 compatibility (no `js.lib.BigInt` there). + **/ + @:native("hrtime.bigint") + function hrtimeBigint():Dynamic; - As with require.main, it will be undefined if there was no entry script. + /** + Alternate way to retrieve require.main. + @deprecated Use `Require.main` instead. **/ + @:deprecated("Use Require.main instead") var mainModule(default, null):Module; /** Send a message to the parent process. - Only available for child processes. See `ChildProcess.send`. **/ - @:overload(function(message:Dynamic, sendHandle:Dynamic, options:ChildProcessSendOptions, ?callback:Error->Void):Bool {}) - @:overload(function(message:Dynamic, sendHandle:Dynamic, ?callback:Error->Void):Bool {}) - function send(message:Dynamic, ?callback:Error->Void):Bool; + @:overload(function(message:Dynamic, sendHandle:ChildProcessSendHandle, options:ChildProcessSendOptions, ?callback:Null->Void):Bool {}) + @:overload(function(message:Dynamic, sendHandle:ChildProcessSendHandle, ?callback:Null->Void):Bool {}) + function send(message:Dynamic, ?callback:Null->Void):Bool; /** Close the IPC channel to parent process. - - Only available for child processes. See `ChildProcess.disconnect`. **/ function disconnect():Void; /** - Disable run-time deprecation warnings. - See `Util.deprecate`. + The `process.emitWarning()` method can be used to emit custom or application specific process warnings. **/ - var noDeprecation:Bool; + @:overload(function(warning:String, ?type:String, ?code:String, ?ctor:Function):Void {}) + @:overload(function(warning:String, options:EmitWarningOptions):Void {}) + function emitWarning(warning:EitherType, ?type:String, ?code:String, ?ctor:Function):Void; /** - Enable logging of deprecation warnings. - See `Util.deprecate`. + Loads environment variables from a `.env` file into `process.env`. **/ - var traceDeprecation:Bool; + function loadEnvFile(?path:String):Void; /** - Throw on deprecated API usage. - See `Util.deprecate`. + Returns the built-in module with the given `id`, or `undefined` if not found. **/ - var throwDeprecation:Bool; + function getBuiltinModule(id:String):Dynamic; + + /** + Sets a user-provided function as the uncaughtException capture callback. + **/ + function setUncaughtExceptionCaptureCallback(fn:NullVoid>):Void; + + /** + Indicates whether a callback has been set using `setUncaughtExceptionCaptureCallback`. + **/ + function hasUncaughtExceptionCaptureCallback():Bool; + + /** + Enable or disable Source Map v3 support for stack traces. + **/ + function setSourceMapsEnabled(value:Bool):Void; + + /** + Reference a value that implements `Symbol.dispose` / ref counting so it keeps the event loop alive. + **/ + function ref(maybeRefable:Dynamic):Void; + + /** + Unreference a previously referenced value. + **/ + function unref(maybeRefable:Dynamic):Void; + + /** + Returns the CPU usage statistics of the current worker thread. + **/ + function threadCpuUsage(?previousValue:CpuUsage):CpuUsage; } typedef MemoryUsage = { rss:Float, heapTotal:Float, - heapUsed:Float + heapUsed:Float, + ?external:Float, + ?arrayBuffers:Float +} + +typedef CpuUsage = { + user:Float, + system:Float +} + +typedef ResourceUsage = { + userCPUTime:Float, + systemCPUTime:Float, + maxRSS:Float, + sharedMemorySize:Float, + unsharedDataSize:Float, + unsharedStackSize:Float, + minorPageFault:Float, + majorPageFault:Float, + swappedOut:Float, + fsRead:Float, + fsWrite:Float, + ipcSent:Float, + ipcReceived:Float, + signalsCount:Float, + voluntaryContextSwitches:Float, + involuntaryContextSwitches:Float } typedef Release = { @@ -372,3 +507,29 @@ typedef Release = { ?libUrl:String, ?lts:String } + +typedef EmitWarningOptions = { + @:optional var type:String; + @:optional var code:String; + @:optional var detail:String; + @:optional var ctor:Function; +} + +/** + Boolean flags describing process feature availability. + + @see https://nodejs.org/api/process.html#processfeatures +**/ +typedef ProcessFeatures = { + var inspector(default, null):Bool; + var debug(default, null):Bool; + var uv(default, null):Bool; + var ipv6(default, null):Bool; + var tls(default, null):Bool; + var tls_alpn(default, null):Bool; + var tls_ocsp(default, null):Bool; + var tls_sni(default, null):Bool; + @:optional var typescript(default, null):EitherType; + @:optional var require_module(default, null):Bool; + @:optional var cached_builtins(default, null):Bool; +} diff --git a/src/js/node/Punycode.hx b/src/js/node/Punycode.hx index cc3a9f94..70949381 100644 --- a/src/js/node/Punycode.hx +++ b/src/js/node/Punycode.hx @@ -22,7 +22,7 @@ package js.node; -@:deprecated("In a future major version of Node.js punycode module will be removed") +@:deprecated("Use Url.domainToASCII / Url.domainToUnicode instead") @:jsRequire("punycode") extern class Punycode { /** @@ -59,7 +59,7 @@ extern class Punycode { static var version(default, null):String; } -@:deprecated +@:deprecated("Use String.fromCodePoint / codePointAt instead") extern class PunycodeUcs2 { /** Creates an array containing the decimal code points of each Unicode character in the string. diff --git a/src/js/node/Querystring.hx b/src/js/node/Querystring.hx index 0d2c4544..a588196e 100644 --- a/src/js/node/Querystring.hx +++ b/src/js/node/Querystring.hx @@ -24,6 +24,7 @@ package js.node; import haxe.DynamicAccess; import haxe.extern.EitherType; +import js.node.Buffer; /** The `querystring` module provides utilities for parsing and formatting URL query strings. @@ -76,7 +77,15 @@ extern class Querystring { @see https://nodejs.org/api/querystring.html#querystring_querystring_unescape_str **/ - static dynamic function unescape(str:String):Dynamic; + static dynamic function unescape(str:String):String; + + /** + The `querystring.unescapeBuffer()` method performs decoding of URL percent-encoded characters + on a `Buffer` of bytes, returning a new `Buffer`. + + @see https://nodejs.org/api/querystring.html + **/ + static function unescapeBuffer(buffer:Buffer, ?decodeSpaces:Bool):Buffer; } /** diff --git a/src/js/node/Readline.hx b/src/js/node/Readline.hx index 2f92cfb8..58d33d96 100644 --- a/src/js/node/Readline.hx +++ b/src/js/node/Readline.hx @@ -26,58 +26,47 @@ import haxe.extern.EitherType; import js.node.readline.*; import js.node.stream.Readable.IReadable; import js.node.stream.Writable.IWritable; +import js.node.web.AbortSignal; /** The readline module provides an interface for reading data from a `Readable` stream (such as `process.stdin`) one line at a time. - @see https://nodejs.org/api/readline.html#readline_readline + @see https://nodejs.org/docs/latest-v24.x/api/readline.html **/ @:jsRequire("readline") extern class Readline { /** The `readline.clearLine()` method Clears current line of given `TTY` stream in a specified direction identified by `dir`. - - @see https://nodejs.org/api/readline.html#readline_readline_clearline_stream_dir_callback **/ static function clearLine(stream:IWritable, dir:ClearLineDirection, ?callback:Void->Void):Bool; /** The `readline.clearScreenDown()` method clears the given `TTY` stream from the current position of the cursor down. - - @see https://nodejs.org/api/readline.html#readline_readline_clearscreendown_stream_callback **/ static function clearScreenDown(stream:IWritable, ?callback:Void->Void):Bool; /** The `readline.createInterface()` method creates a new `readline.Interface` instance. - - @see https://nodejs.org/api/readline.html#readline_readline_createinterface_options **/ @:overload(function(input:IReadable, ?output:IWritable, ?completer:ReadlineCompleterCallback, ?terminal:Bool):Interface {}) static function createInterface(options:ReadlineOptions):Interface; /** The `readline.cursorTo()` method moves cursor to the specified position in a given `TTY` `stream`. - - @see https://nodejs.org/api/readline.html#readline_readline_cursorto_stream_x_y_callback **/ static function cursorTo(stream:IWritable, x:Int, ?y:Int, ?callback:Void->Void):Bool; /** The `readline.emitKeypressEvents()` method causes the given `Readable` stream to begin emitting `'keypress'` events corresponding to received input. - - @see https://nodejs.org/api/readline.html#readline_readline_emitkeypressevents_stream_interface **/ static function emitKeypressEvents(stream:IReadable, ?iface:Interface):Void; /** The `readline.moveCursor()` method moves the cursor relative to its current position in a given `TTY` `stream`. - - @see https://nodejs.org/api/readline.html#readline_readline_movecursor_stream_dx_dy_callback **/ static function moveCursor(stream:IWritable, dx:Int, dy:Int, ?callback:Void->Void):Bool; } @@ -85,7 +74,7 @@ extern class Readline { /** Options object used by `Readline.createInterface`. - @see https://nodejs.org/api/readline.html#readline_readline_createinterface_options + @see https://nodejs.org/docs/latest-v24.x/api/readline.html#readlinecreateinterfaceoptions **/ typedef ReadlineOptions = { /** @@ -100,75 +89,64 @@ typedef ReadlineOptions = { /** An optional function used for Tab autocompletion. - - @see https://nodejs.org/api/readline.html#readline_use_of_the_completer_function **/ @:optional var completer:ReadlineCompleterCallback; /** `true` if the `input` and `output` streams should be treated like a TTY, and have ANSI/VT100 escape codes written to it. - - Default: checking `isTTY` on the `output` stream upon instantiation. **/ @:optional var terminal:Bool; + /** + Initial list of history lines. + **/ + @:optional var history:Array; + /** Maximum number of history lines retained. To disable the history set this value to `0`. - This option makes sense only if `terminal` is set to `true` by the user or by an internal `output` check, - otherwise the history caching mechanism is not initialized at all. - - Default: `30`. **/ @:optional var historySize:Int; /** - The prompt string to use. - - Default: `'> '`. + The prompt string to use. Default: `'> '`. **/ @:optional var prompt:String; /** If the delay between `\r` and `\n` exceeds `crlfDelay` milliseconds, both `\r` and `\n` will be treated as separate end-of-line input. - `crlfDelay` will be coerced to a number no less than `100`. - It can be set to `Infinity`, in which case `\r` followed by `\n` will always be considered a single newline - (which may be reasonable for reading files with `\r\n` line delimiter). - - Default: `100`. **/ - @:optional var crlfDelay:Int; + @:optional var crlfDelay:Float; /** If `true`, when a new input line added to the history list duplicates an older one, this removes the older line from the list. - - Default: `false`. **/ @:optional var removeHistoryDuplicates:Bool; /** - The duration `readline` will wait for a character (when reading an ambiguous key sequence in milliseconds one - that can both form a complete key sequence using the input read so far and can take additional input to complete - a longer key sequence). - - Default: `500`. + The duration `readline` will wait for a character (when reading an ambiguous key sequence) in milliseconds. **/ @:optional var escapeCodeTimeout:Int; + + /** + The number of spaces a tab is equal to (minimum 1). Default: `8`. + **/ + @:optional var tabSize:Int; + + /** + Allows closing the interface using an `AbortSignal`. + Aborting the signal will internally call `close` on the interface. + **/ + @:optional var signal:AbortSignal; } -#if haxe4 typedef ReadlineCompleterCallback = (line:String) -> Array, String>>; -#else -typedef ReadlineCompleterCallback = String->Array, String>>; -#end /** Enumeration of possible directions for `Readline.clearLine`. - - @see https://nodejs.org/api/readline.html#readline_readline_clearline_stream_dir_callback **/ enum abstract ClearLineDirection(Int) from Int to Int { /** diff --git a/src/js/node/ReadlinePromises.hx b/src/js/node/ReadlinePromises.hx new file mode 100644 index 00000000..2a5066a4 --- /dev/null +++ b/src/js/node/ReadlinePromises.hx @@ -0,0 +1,125 @@ +/* + * Copyright (C)2014-2020 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package js.node; + +import haxe.extern.EitherType; +import js.lib.Promise; +import js.node.readline.PromisesInterface; +import js.node.stream.Readable.IReadable; +import js.node.stream.Writable.IWritable; +import js.node.web.AbortSignal; + +/** + Completer result: matching entries, then the substring used for matching. +**/ +typedef ReadlinePromisesCompleterResult = Array, String>>; + +/** + Tab autocompletion for `readline/promises`. + Unlike the callback API, the completer may return a `Promise`. +**/ +typedef ReadlinePromisesCompleterCallback = (line:String) -> EitherType>; + +/** + Options for `ReadlinePromises.createInterface`. + + Same surface as `ReadlineOptions`, but `completer` may return a `Promise`. + + @see https://nodejs.org/docs/latest-v24.x/api/readline.html#readlinepromisescreateinterfaceoptions +**/ +typedef ReadlinePromisesOptions = { + /** + The `Readable` stream to listen to. + **/ + var input:IReadable; + + /** + The `Writable` stream to write readline data to. + **/ + @:optional var output:IWritable; + + /** + An optional function used for Tab autocompletion. + May return a `Promise` resolving to the completer result. + **/ + @:optional var completer:ReadlinePromisesCompleterCallback; + + /** + `true` if the `input` and `output` streams should be treated like a TTY. + **/ + @:optional var terminal:Bool; + + /** + Initial list of history lines. + **/ + @:optional var history:Array; + + /** + Maximum number of history lines retained. + **/ + @:optional var historySize:Int; + + /** + The prompt string to use. + **/ + @:optional var prompt:String; + + /** + Delay threshold for treating `\r\n` as a single newline. + **/ + @:optional var crlfDelay:Float; + + /** + If `true`, remove older duplicate history entries. + **/ + @:optional var removeHistoryDuplicates:Bool; + + /** + Ambiguous key sequence timeout in milliseconds. + **/ + @:optional var escapeCodeTimeout:Int; + + /** + The number of spaces a tab is equal to (minimum 1). + **/ + @:optional var tabSize:Int; + + /** + Allows closing the interface using an `AbortSignal`. + **/ + @:optional var signal:AbortSignal; +} + +/** + The `readline/promises` API provides an alternative set of interfaces that return promises. + + @see https://nodejs.org/docs/latest-v24.x/api/readline.html#promises-api +**/ +@:jsRequire("readline/promises") +extern class ReadlinePromises { + /** + Creates a new `readlinePromises.Interface` instance. + **/ + @:overload(function(input:IReadable, ?output:IWritable, ?completer:ReadlinePromisesCompleterCallback, ?terminal:Bool):PromisesInterface {}) + static function createInterface(options:ReadlinePromisesOptions):PromisesInterface; +} diff --git a/src/js/node/Repl.hx b/src/js/node/Repl.hx index d15e6fbe..08fa0686 100644 --- a/src/js/node/Repl.hx +++ b/src/js/node/Repl.hx @@ -23,132 +23,95 @@ package js.node; import haxe.DynamicAccess; +import js.lib.Error; +import js.lib.Symbol; import js.node.repl.REPLServer; import js.node.stream.Readable.IReadable; import js.node.stream.Writable.IWritable; -#if haxe4 -import js.lib.Error; -import js.lib.Symbol; -#else -import js.Error; -#end /** The `repl` module provides a Read-Eval-Print-Loop (REPL) implementation that is available both as a standalone program or includible in other applications. - @see https://nodejs.org/api/repl.html#repl_repl + @see https://nodejs.org/docs/latest-v24.x/api/repl.html **/ @:jsRequire("repl") extern class Repl { /** The `repl.start()` method creates and starts a `repl.REPLServer` instance. - - @see https://nodejs.org/api/repl.html#repl_repl_start_options **/ @:overload(function(prompt:String):REPLServer {}) - static function start(options:ReplOptions):REPLServer; + static function start(?options:ReplOptions):REPLServer; /** Evaluates expressions in sloppy mode. - - @see https://nodejs.org/api/repl.html#repl_repl_start_options **/ - #if haxe4 static final REPL_MODE_SLOPPY:Symbol; - #else - static var REPL_MODE_SLOPPY(default, never):Dynamic; - #end /** Evaluates expressions in strict mode. This is equivalent to prefacing every repl statement with `'use strict'`. - - @see https://nodejs.org/api/repl.html#repl_repl_start_options **/ - #if haxe4 static final REPL_MODE_STRICT:Symbol; - #else - static var REPL_MODE_STRICT(default, never):Dynamic; - #end } /** Options object used by `Repl.start`. - @see https://nodejs.org/api/repl.html#repl_repl_start_options + @see https://nodejs.org/docs/latest-v24.x/api/repl.html#replstartoptions **/ typedef ReplOptions = { /** - The input prompt to display. - - Default: `'> '` (with a trailing space). + The input prompt to display. Default: `'> '` (with a trailing space). **/ @:optional var prompt:String; /** - The `Readable` stream from which REPL input will be read. - - Default: `process.stdin`. + The `Readable` stream from which REPL input will be read. Default: `process.stdin`. **/ @:optional var input:IReadable; /** - The `Writable` stream to which REPL output will be written. - - Default: `process.stdout`. + The `Writable` stream to which REPL output will be written. Default: `process.stdout`. **/ @:optional var output:IWritable; /** If `true`, specifies that the `output` should be treated as a TTY terminal. - - Default: checking the value of the `isTTY` property on the `output` stream upon instantiation. **/ @:optional var terminal:Bool; /** The function to be used when evaluating each given line of input. - Default: an async wrapper for the JavaScript `eval()` function. + + // TODO(section-5): replace DynamicAccess/Dynamic result with a typed REPL context model **/ - #if haxe4 @:optional var eval:(code:String, context:DynamicAccess, file:String, cb:(error:Null, ?result:Dynamic) -> Void) -> Void; - #else - @:optional var eval:String->DynamicAccess->String->(Null->?Dynamic->Void)->Void; - #end /** If `true`, specifies that the default `writer` function should include ANSI color styling to REPL output. - If a custom `writer` function is provided then this has no effect. - - Default: checking color support on the `output` stream if the REPL instance's `terminal` value is `true`. **/ @:optional var useColors:Bool; /** - If `true`, specifies that the default evaluation function will use the JavaScript `global` as the context as - opposed to creating a new separate context for the REPL instance. - The node CLI REPL sets this value to `true`. - - Default: `false`. + If `true`, specifies that the default evaluation function will use the JavaScript `global` as the context. **/ @:optional var useGlobal:Bool; /** If `true`, specifies that the default writer will not output the return value of a command if it evaluates to `undefined`. - - Default: `false`. **/ @:optional var ignoreUndefined:Bool; /** The function to invoke to format the output of each command before writing to `output`. - Default: `util.inspect()`. + + // TODO(section-5): type writer as (value:Dynamic) -> String **/ - @:optional var writer:Dynamic->Void; + @:optional var writer:Dynamic->Dynamic; /** An optional function used for custom Tab auto completion. @@ -160,17 +123,16 @@ typedef ReplOptions = { (sloppy) mode. Acceptable values are `repl.REPL_MODE_SLOPPY` or `repl.REPL_MODE_STRICT`. **/ - #if haxe4 @:optional var replMode:Symbol; - #else - @:optional var replMode:Dynamic; - #end /** Stop evaluating the current piece of code when `SIGINT` is received, i.e. `Ctrl+C` is pressed. This cannot be used together with a custom `eval` function. - - Default: `false`. **/ @:optional var breakEvalOnSigint:Bool; + + /** + If `true`, show preview of the results when inputting. Default depends on Node version / terminal. + **/ + @:optional var preview:Bool; } diff --git a/src/js/node/Report.hx b/src/js/node/Report.hx index 8d413738..ce755cc3 100644 --- a/src/js/node/Report.hx +++ b/src/js/node/Report.hx @@ -1,54 +1,63 @@ -package js.node; - -#if haxe4 -import js.lib.Error; -#else -import js.Error; -#end - -extern class Report { - /** - If the reports are written in compact mode. - **/ - var compact:Bool; - - /** - The directory in which the reports are written. - **/ - var directory:String; - - /** - The file in which the reports are written. - **/ - var filename:String; - - /** - Returns the diagnostic report as an object. Optionally from an error object. - **/ - function getReport(?err:Error):Dynamic; - - /** - When the diagnostic report was generated in case of fatal errors. - **/ - var reportOnFatalError:Bool; - - /** - If the diagnostic report was generated by receiving a signal. - **/ - var reportOnSignal:Bool; - - /** - When the diagnostic report was generated in case of a uncaught exception. - **/ - var reportOnUncaughtException:Bool; - - /** - The signal that triggered the diagnostic report. - **/ - var signal:String; - - /** - Writes a diagnostic report to a file. - **/ - function writeReport(?filename:String, ?err:Error):String; -} +package js.node; + +import js.lib.Error; + +/** + Diagnostic report API available via `process.report`. + + @see https://nodejs.org/api/process.html#processreport +**/ +extern class Report { + /** + If the reports are written in compact mode. + **/ + var compact:Bool; + + /** + The directory in which the reports are written. + **/ + var directory:String; + + /** + The file in which the reports are written. + **/ + var filename:String; + + /** + Returns the diagnostic report as an object. Optionally from an error object. + **/ + function getReport(?err:Error):Dynamic; + + /** + When the diagnostic report was generated in case of fatal errors. + **/ + var reportOnFatalError:Bool; + + /** + If the diagnostic report was generated by receiving a signal. + **/ + var reportOnSignal:Bool; + + /** + When the diagnostic report was generated in case of a uncaught exception. + **/ + var reportOnUncaughtException:Bool; + + /** + If `true`, the environment variables are excluded from the report. + Default: `false`. + + @see https://nodejs.org/api/process.html#processreportexcludeenv + **/ + var excludeEnv:Bool; + + /** + The signal that triggered the diagnostic report. + **/ + var signal:String; + + /** + Writes a diagnostic report to a file. + **/ + function writeReport(?filename:String, ?err:Error):String; +} diff --git a/src/js/node/Require.hx b/src/js/node/Require.hx index 012d9f78..4bf7deb8 100644 --- a/src/js/node/Require.hx +++ b/src/js/node/Require.hx @@ -56,7 +56,7 @@ extern class Require { Since the `Module` system is locked, this feature will probably never go away. However, it may have subtle bugs and complexities that are best left untouched. **/ - @:deprecated + @:deprecated("Use compiling to JavaScript ahead of time instead") static var extensions(default, null):DynamicAccess; /** diff --git a/src/js/node/Sea.hx b/src/js/node/Sea.hx new file mode 100644 index 00000000..daae3977 --- /dev/null +++ b/src/js/node/Sea.hx @@ -0,0 +1,88 @@ +/* + * Copyright (C)2014-2020 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package js.node; + +import js.lib.ArrayBuffer; +import js.node.web.Blob; + +/** + Built-in helpers for scripts running inside a single-executable application (SEA). + + Stability: 1.1 - Active development. + + @see https://nodejs.org/docs/latest-v24.x/api/single-executable-applications.html#single-executable-application-api +**/ +@:jsRequire("node:sea") +extern class Sea { + /** + Whether this script is running inside a single-executable application. + + @see https://nodejs.org/docs/latest-v24.x/api/single-executable-applications.html#seaissea + **/ + static function isSea():Bool; + + /** + Retrieve a bundled asset by key. + + Without `encoding`, returns a copy of the asset as an `ArrayBuffer`. + With `encoding`, returns a decoded string (any encoding supported by `TextDecoder`). + + @see https://nodejs.org/docs/latest-v24.x/api/single-executable-applications.html#seagetassetkey-encoding + **/ + @:overload(function(key:String, encoding:String):String {}) + static function getAsset(key:String):ArrayBuffer; + + /** + Retrieve a bundled asset as a `Blob`. + + @see https://nodejs.org/docs/latest-v24.x/api/single-executable-applications.html#seagetassetasblobkey-options + **/ + static function getAssetAsBlob(key:String, ?options:SeaBlobOptions):Blob; + + /** + Retrieve the raw asset without copying. + + @see https://nodejs.org/docs/latest-v24.x/api/single-executable-applications.html#seagetrawassetkey + **/ + static function getRawAsset(key:String):ArrayBuffer; + + /** + Keys of all assets embedded in the executable. + Throws when not running inside a SEA. + + Added in: v24.8.0 + + @see https://nodejs.org/docs/latest-v24.x/api/single-executable-applications.html#seagetassetkeys + **/ + static function getAssetKeys():Array; +} + +/** + Options for `Sea.getAssetAsBlob`. +**/ +typedef SeaBlobOptions = { + /** + Optional MIME type for the blob. + **/ + @:optional var type:String; +} diff --git a/src/js/node/Sqlite.hx b/src/js/node/Sqlite.hx new file mode 100644 index 00000000..a2b71dde --- /dev/null +++ b/src/js/node/Sqlite.hx @@ -0,0 +1,131 @@ +/* + * Copyright (C)2014-2020 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package js.node; + +import haxe.extern.EitherType; +import js.lib.Promise; +import js.node.buffer.Buffer; +import js.node.sqlite.DatabaseSync; +import js.node.url.URL; + +/** + The `node:sqlite` module facilitates working with SQLite databases. + + Stability: 1.2 - Release candidate. + + Available only under the `node:` scheme. + + @see https://nodejs.org/docs/latest-v24.x/api/sqlite.html +**/ +@:jsRequire("node:sqlite") +extern class Sqlite { + /** + Constants used by authorizer callbacks and changeset conflict handlers. + **/ + static var constants(default, never):SqliteConstants; + + /** + Make a backup of `sourceDb` to `path`. + + @see https://nodejs.org/docs/latest-v24.x/api/sqlite.html#sqlitebackupsourcedb-path-options + **/ + static function backup(sourceDb:DatabaseSync, path:SqlitePath, ?options:SqliteBackupOptions):Promise; +} + +/** + Path accepted by SQLite open / backup APIs. +**/ +typedef SqlitePath = EitherType>; + +/** + Options for `Sqlite.backup`. +**/ +typedef SqliteBackupOptions = { + @:optional var source:String; + @:optional var target:String; + @:optional var rate:Int; + @:optional var progress:SqliteBackupProgress->Void; +} + +/** + Progress info for `Sqlite.backup`. +**/ +typedef SqliteBackupProgress = { + var totalPages:Float; + var remainingPages:Float; +} + +/** + Constants exported by `node:sqlite`. + + Includes authorizer action codes, authorizer results, and changeset conflict codes. +**/ +typedef SqliteConstants = { + var SQLITE_OK(default, never):Int; + var SQLITE_DENY(default, never):Int; + var SQLITE_IGNORE(default, never):Int; + + var SQLITE_CHANGESET_OMIT(default, never):Int; + var SQLITE_CHANGESET_REPLACE(default, never):Int; + var SQLITE_CHANGESET_ABORT(default, never):Int; + var SQLITE_CHANGESET_DATA(default, never):Int; + var SQLITE_CHANGESET_NOTFOUND(default, never):Int; + var SQLITE_CHANGESET_CONFLICT(default, never):Int; + var SQLITE_CHANGESET_CONSTRAINT(default, never):Int; + var SQLITE_CHANGESET_FOREIGN_KEY(default, never):Int; + + var SQLITE_CREATE_INDEX(default, never):Int; + var SQLITE_CREATE_TABLE(default, never):Int; + var SQLITE_CREATE_TEMP_INDEX(default, never):Int; + var SQLITE_CREATE_TEMP_TABLE(default, never):Int; + var SQLITE_CREATE_TEMP_TRIGGER(default, never):Int; + var SQLITE_CREATE_TEMP_VIEW(default, never):Int; + var SQLITE_CREATE_TRIGGER(default, never):Int; + var SQLITE_CREATE_VIEW(default, never):Int; + var SQLITE_DELETE(default, never):Int; + var SQLITE_DROP_INDEX(default, never):Int; + var SQLITE_DROP_TABLE(default, never):Int; + var SQLITE_DROP_TEMP_INDEX(default, never):Int; + var SQLITE_DROP_TEMP_TABLE(default, never):Int; + var SQLITE_DROP_TEMP_TRIGGER(default, never):Int; + var SQLITE_DROP_TEMP_VIEW(default, never):Int; + var SQLITE_DROP_TRIGGER(default, never):Int; + var SQLITE_DROP_VIEW(default, never):Int; + var SQLITE_INSERT(default, never):Int; + var SQLITE_PRAGMA(default, never):Int; + var SQLITE_READ(default, never):Int; + var SQLITE_SELECT(default, never):Int; + var SQLITE_TRANSACTION(default, never):Int; + var SQLITE_UPDATE(default, never):Int; + var SQLITE_ATTACH(default, never):Int; + var SQLITE_DETACH(default, never):Int; + var SQLITE_ALTER_TABLE(default, never):Int; + var SQLITE_REINDEX(default, never):Int; + var SQLITE_ANALYZE(default, never):Int; + var SQLITE_CREATE_VTABLE(default, never):Int; + var SQLITE_DROP_VTABLE(default, never):Int; + var SQLITE_FUNCTION(default, never):Int; + var SQLITE_SAVEPOINT(default, never):Int; + var SQLITE_COPY(default, never):Int; + var SQLITE_RECURSIVE(default, never):Int; +} diff --git a/src/js/node/Stream.hx b/src/js/node/Stream.hx index 2aa7631b..698d0305 100644 --- a/src/js/node/Stream.hx +++ b/src/js/node/Stream.hx @@ -1,5 +1,5 @@ /* - * Copyright (C)2014-2020 Haxe Foundation + * Copyright (C)2014-2026 Haxe Foundation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -23,24 +23,47 @@ package js.node; import haxe.extern.Rest; +import js.lib.Error; +import js.lib.Promise; import js.node.events.EventEmitter; +import js.node.stream.Duplex.IDuplex; import js.node.stream.Readable.IReadable; import js.node.stream.Writable.IWritable; -#if haxe4 -import js.lib.Error; -import js.lib.Promise; -#else -import js.Error; -import js.Promise; -#end +import js.node.web.AbortSignal; /** Base class for all streams. + Also the `stream` module façade exporting stream helpers and constructors. + + @see https://nodejs.org/api/stream.html **/ @:jsRequire("stream") // the module itself is also a class extern class Stream> extends EventEmitter implements IStream { private function new(); + /** + Is `true` after `'close'` has been emitted. + + @see https://nodejs.org/api/stream.html#readableclosed + @see https://nodejs.org/api/stream.html#writableclosed + **/ + var closed(default, null):Bool; + + /** + Returns the error if the stream has been destroyed with an error. + + @see https://nodejs.org/api/stream.html#readableerrored + @see https://nodejs.org/api/stream.html#writableerrored + **/ + var errored(default, null):Null; + + /** + Promise-based stream helpers (`stream/promises`). + + @see https://nodejs.org/api/stream.html#streams-promises-api + **/ + static final promises:StreamPromises; + /** A module method to pipe between streams forwarding errors and properly cleaning up and provide a callback when the pipeline is complete. @@ -62,6 +85,167 @@ extern class Stream> extends EventEmitter implements @:overload(function(readable:IReadable, writable1:IWritable, writable2:IWritable, writable3:IWritable, writable4:IWritable, writable5:IWritable, writable6:IWritable, writable7:IWritable, writable8:IWritable, callback:Null->Void):Void {}) static function pipeline(readable:IReadable, streams:Rest):Promise; + + /** + A module method to wait for a readable or writable stream to finish. + + The callback form returns a cleanup function that removes registered listeners. + + @see https://nodejs.org/api/stream.html#streamfinishedstream-options-callback + **/ + @:overload(function(stream:IStream, callback:Null->Void):Void->Void {}) + @:overload(function(stream:IStream, options:StreamFinishedOptions, callback:Null->Void):Void->Void {}) + static function finished(stream:IStream, ?options:StreamFinishedOptions):Promise; + + /** + Combines two or more streams into a `Duplex` stream that writes to the first + stream and reads from the last. + + Pass `StreamComposeOptions` (for example `{signal: ...}`) as the last argument when needed. + + @see https://nodejs.org/api/stream.html#streamcomposestreams + **/ + static function compose(streams:Rest):IDuplex; + + /** + Returns a pair of connected Duplex streams where data written to either side + appears on the other. + + @see https://nodejs.org/api/stream.html#streamduplexpairoptions + **/ + static function duplexPair(?options:js.node.stream.Duplex.DuplexNewOptions):Array; + + /** + Attaches an AbortSignal to a readable or writable stream so destroying + the stream when the signal is aborted. + + @see https://nodejs.org/api/stream.html#streamaddabortsignalsignal-stream + **/ + static function addAbortSignal(signal:AbortSignal, stream:IStream):IStream; + + /** + Destroys the stream, optionally with an error. + + Exported by the `stream` module (undocumented helper used by pipeline cleanup). + **/ + static function destroy(stream:IStream, ?error:Error):Void; + + /** + Returns the default highWaterMark used by streams. + + @see https://nodejs.org/api/stream.html#streamgetdefaulthighwatermarkobjectmode + **/ + static function getDefaultHighWaterMark(objectMode:Bool):Int; + + /** + Sets the default highWaterMark used by streams. + + @see https://nodejs.org/api/stream.html#streamsetdefaulthighwatermarkobjectmode-value + **/ + static function setDefaultHighWaterMark(objectMode:Bool, value:Int):Void; + + /** + Returns whether the stream is readable. + + Returns `null` if `stream` is not a valid readable stream. + + @see https://nodejs.org/api/stream.html#streamisreadablestream + **/ + static function isReadable(stream:Any):Null; + + /** + Returns whether the stream is writable. + + Returns `null` if `stream` is not a valid writable stream. + + @see https://nodejs.org/api/stream.html#streamiswritablestream + **/ + static function isWritable(stream:Any):Null; + + /** + Returns whether the stream has been destroyed. + + Exported by the `stream` module (undocumented helper; available since Node 16+). + **/ + static function isDestroyed(stream:Any):Bool; + + /** + Returns whether the stream has been read from or cancelled. + + Also available as `Readable.isDisturbed`. + + @see https://nodejs.org/api/stream.html#streamreadableisdisturbedstream + **/ + static function isDisturbed(stream:Any):Bool; + + /** + Returns whether the stream has encountered an error. + + @see https://nodejs.org/api/stream.html#streamiserroredstream + **/ + static function isErrored(stream:Any):Bool; +} + +/** + Options for `Stream.finished`. +**/ +typedef StreamFinishedOptions = { + /** + If set to `false`, then a call to `emit('error', err)` is not treated as finished. + Default: `true`. + **/ + @:optional var error:Bool; + + /** + When set to `false`, the callback / Promise will resolve when the stream ends + even though the stream might still be readable. + Default: `true`. + **/ + @:optional var readable:Bool; + + /** + When set to `false`, the callback / Promise will resolve when the stream ends + even though the stream might still be writable. + Default: `true`. + **/ + @:optional var writable:Bool; + + /** + Allows aborting the wait for the stream to finish. The underlying stream is not + aborted if the signal is aborted. The callback / Promise rejects with an `AbortError`. + **/ + @:optional var signal:AbortSignal; + + /** + If `true`, removes the listeners registered by this function before the Promise is fulfilled. + Only used by the Promise form of `finished`. Default: `false`. + **/ + @:optional var cleanup:Bool; +} + +/** + Options for `Stream.pipeline` / `StreamPromises.pipeline`. +**/ +typedef StreamPipelineOptions = { + /** + If specified, the pipeline will abort when the signal is aborted. + **/ + @:optional var signal:AbortSignal; + + /** + End the destination stream when the source stream ends. Default: `true`. + **/ + @:optional var end:Bool; +} + +/** + Options for `Stream.compose`. +**/ +typedef StreamComposeOptions = { + /** + Allows destroying the stream if the signal is aborted. + **/ + @:optional var signal:AbortSignal; } /** @@ -70,4 +254,14 @@ extern class Stream> extends EventEmitter implements See `Stream` for actual class. **/ @:remove -extern interface IStream extends IEventEmitter {} +extern interface IStream extends IEventEmitter { + /** + Is `true` after `'close'` has been emitted. + **/ + var closed(default, null):Bool; + + /** + Returns the error if the stream has been destroyed with an error. + **/ + var errored(default, null):Null; +} diff --git a/src/js/node/StreamPromises.hx b/src/js/node/StreamPromises.hx new file mode 100644 index 00000000..28d64ea3 --- /dev/null +++ b/src/js/node/StreamPromises.hx @@ -0,0 +1,72 @@ +/* + * Copyright (C)2014-2026 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package js.node; + +import haxe.extern.Rest; +import js.lib.Promise; +import js.node.Stream; +import js.node.stream.Readable.IReadable; +import js.node.stream.Writable.IWritable; + +/** + The `stream/promises` API provides an alternative set of asynchronous stream + utilities that return `Promise` objects rather than using callbacks. + + Accessible via `require('stream/promises')` or `require('stream').promises`. + + @see https://nodejs.org/api/stream.html#streams-promises-api +**/ +@:jsRequire("stream/promises") +extern class StreamPromises { + /** + A module method to pipe between streams forwarding errors and properly cleaning up, + returning a Promise when the pipeline is complete. + + Requires at least a source and a destination. Pass `options` (including `signal`) + as the last argument when needed. + + @see https://nodejs.org/api/stream.html#streampipelinestreams-options + **/ + @:overload(function(readable:IReadable, writable1:IWritable, ?options:StreamPipelineOptions):Promise {}) + @:overload(function(readable:IReadable, writable1:IWritable, writable2:IWritable, ?options:StreamPipelineOptions):Promise {}) + @:overload(function(readable:IReadable, writable1:IWritable, writable2:IWritable, writable3:IWritable, ?options:StreamPipelineOptions):Promise {}) + @:overload(function(readable:IReadable, writable1:IWritable, writable2:IWritable, writable3:IWritable, writable4:IWritable, + ?options:StreamPipelineOptions):Promise {}) + @:overload(function(readable:IReadable, writable1:IWritable, writable2:IWritable, writable3:IWritable, writable4:IWritable, writable5:IWritable, + ?options:StreamPipelineOptions):Promise {}) + @:overload(function(readable:IReadable, writable1:IWritable, writable2:IWritable, writable3:IWritable, writable4:IWritable, writable5:IWritable, + writable6:IWritable, ?options:StreamPipelineOptions):Promise {}) + @:overload(function(readable:IReadable, writable1:IWritable, writable2:IWritable, writable3:IWritable, writable4:IWritable, writable5:IWritable, + writable6:IWritable, writable7:IWritable, ?options:StreamPipelineOptions):Promise {}) + @:overload(function(readable:IReadable, writable1:IWritable, writable2:IWritable, writable3:IWritable, writable4:IWritable, writable5:IWritable, + writable6:IWritable, writable7:IWritable, writable8:IWritable, ?options:StreamPipelineOptions):Promise {}) + static function pipeline(readable:IReadable, streams:Rest):Promise; + + /** + Returns a Promise that fulfills when the stream is no longer readable, + writable or has experienced an error or a premature close event. + + @see https://nodejs.org/api/stream.html#streamfinishedstream-options + **/ + static function finished(stream:IStream, ?options:StreamFinishedOptions):Promise; +} diff --git a/src/js/node/StringDecoder.hx b/src/js/node/StringDecoder.hx index ec8a33a0..2b4157e0 100644 --- a/src/js/node/StringDecoder.hx +++ b/src/js/node/StringDecoder.hx @@ -22,11 +22,7 @@ package js.node; -#if haxe4 import js.lib.ArrayBufferView; -#else -import js.html.ArrayBufferView; -#end /** The `string_decoder` module provides an API for decoding `Buffer` objects into strings in a manner that preserves @@ -56,7 +52,7 @@ extern class StringDecoder { /** Returns a decoded string, ensuring that any incomplete multibyte characters at the end of the `Buffer`, or - `TypedArray`, or `DataViewor` are omitted from the returned string and stored in an internal buffer for the next + `TypedArray`, or `DataView` are omitted from the returned string and stored in an internal buffer for the next call to `stringDecoder.write()` or `stringDecoder.end()`. @see https://nodejs.org/api/string_decoder.html#string_decoder_stringdecoder_write_buffer diff --git a/src/js/node/Test.hx b/src/js/node/Test.hx new file mode 100644 index 00000000..aae8e702 --- /dev/null +++ b/src/js/node/Test.hx @@ -0,0 +1,541 @@ +/* + * Copyright (C)2014-2020 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package js.node; + +import haxe.Constraints.Function; +import haxe.DynamicAccess; +import haxe.extern.EitherType; +import js.node.web.AbortSignal; +import js.node.test.ItFunction; +import js.node.test.MockTracker; +import js.node.test.SuiteContext; +import js.node.test.SuiteFunction; +import js.node.test.TestContext; +import js.node.test.TestsStream; +import js.lib.Error; +import js.lib.Promise; +import js.lib.RegExp; + +/** + The `node:test` module facilitates the creation of JavaScript tests. + + This module is only available under the `node:` scheme. + + These externs target **Node.js 24+ Active LTS**. Dual-LTS APIs such as + `expectFailure`, `run({ randomize })`, and `TestContext.workerId` are typed + without version gates; older LTS releases may not provide them at runtime. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html +**/ +@:jsRequire("node:test") +extern class Test { + /** + The `test()` function creates a test whose lifecycle is managed by the test runner. + + Each invocation results in reporting the test to the test runner. + Returns a `Promise` that fulfills once the test completes (or immediately if + called within a suite). + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#testname-options-fn + **/ + @:selfCall + @:overload(function(fn:TestCallback):Promise {}) + @:overload(function(name:String, fn:TestCallback):Promise {}) + @:overload(function(options:TestOptions, fn:TestCallback):Promise {}) + static function test(?name:String, ?options:TestOptions, ?fn:TestCallback):Promise; + + /** + Shorthand for skipping a test: `test(name, { skip: true }[, fn])`. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#testskipname-options-fn + **/ + @:overload(function(fn:TestCallback):Promise {}) + @:overload(function(name:String, fn:TestCallback):Promise {}) + @:overload(function(options:TestOptions, fn:TestCallback):Promise {}) + static function skip(?name:String, ?options:TestOptions, ?fn:TestCallback):Promise; + + /** + Shorthand for marking a test as `TODO`: `test(name, { todo: true }[, fn])`. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#testtodoname-options-fn + **/ + @:overload(function(fn:TestCallback):Promise {}) + @:overload(function(name:String, fn:TestCallback):Promise {}) + @:overload(function(options:TestOptions, fn:TestCallback):Promise {}) + static function todo(?name:String, ?options:TestOptions, ?fn:TestCallback):Promise; + + /** + Shorthand for marking a test as `only`: `test(name, { only: true }[, fn])`. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#testonlyname-options-fn + **/ + @:overload(function(fn:TestCallback):Promise {}) + @:overload(function(name:String, fn:TestCallback):Promise {}) + @:overload(function(options:TestOptions, fn:TestCallback):Promise {}) + static function only(?name:String, ?options:TestOptions, ?fn:TestCallback):Promise; + + /** + Shorthand for expecting a test to fail: `test(name, { expectFailure: true }[, fn])`. + + Added in: v24.14.0 + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#expecting-tests-to-fail + **/ + @:overload(function(fn:TestCallback):Promise {}) + @:overload(function(name:String, fn:TestCallback):Promise {}) + @:overload(function(options:TestOptions, fn:TestCallback):Promise {}) + static function expectFailure(?name:String, ?options:TestOptions, ?fn:TestCallback):Promise; + + /** + Alias for `suite()`. Suites group related tests. + + Supports `.skip`, `.todo`, `.only`, and `.expectFailure` shorthands. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#describename-options-fn + **/ + static var describe(default, never):SuiteFunction; + + /** + Creates a suite whose lifecycle is managed by the test runner. + + Supports `.skip`, `.todo`, `.only`, and `.expectFailure` shorthands. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#suitename-options-fn + **/ + static var suite(default, never):SuiteFunction; + + /** + Alias for `test()`. + + Supports `.skip`, `.todo`, `.only`, and `.expectFailure` shorthands. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#itname-options-fn + **/ + static var it(default, never):ItFunction; + + /** + Creates a hook that runs before executing a suite. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#beforefn-options + **/ + @:overload(function(fn:HookCallback):Void {}) + static function before(?fn:HookCallback, ?options:HookOptions):Void; + + /** + Creates a hook that runs after executing a suite. + Guaranteed to run even if tests within the suite fail. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#afterfn-options + **/ + @:overload(function(fn:HookCallback):Void {}) + static function after(?fn:HookCallback, ?options:HookOptions):Void; + + /** + Creates a hook that runs before each test in the current suite. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#beforeeachfn-options + **/ + @:overload(function(fn:HookCallback):Void {}) + static function beforeEach(?fn:HookCallback, ?options:HookOptions):Void; + + /** + Creates a hook that runs after each test in the current suite. + Runs even if the test fails. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#aftereachfn-options + **/ + @:overload(function(fn:HookCallback):Void {}) + static function afterEach(?fn:HookCallback, ?options:HookOptions):Void; + + /** + Top-level `MockTracker` instance for the process. + + Each test also provides its own tracker via `TestContext.mock`. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#class-mocktracker + **/ + static var mock(default, never):MockTracker; + + /** + Object whose methods configure default snapshot settings in the current process. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#snapshot + **/ + static var snapshot(default, never):Snapshot; + + /** + Object whose methods configure available assertions on `TestContext` objects + in the current process. + + Methods from `node:assert` and snapshot testing functions are available on + `TestContext.assert` by default; see `js.node.Assert` for the assert API. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#assert + **/ + static var assert(default, never):TestAssert; + + /** + Programmatically run tests and return a stream of test reporter events. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#runoptions + **/ + static function run(?options:RunOptions):TestsStream; +} + +/** + Callback for a test created with `test()` / `it()` / `TestContext.test()`. + + May be synchronous, return a `Promise`, or accept a Node-style `done` callback + as the second argument. +**/ +typedef TestCallback = EitherTypeDynamic, TestContext->(Null->Void)->Dynamic>; + +/** + Callback for a suite created with `suite()` / `describe()`. +**/ +typedef SuiteCallback = EitherTypeDynamic, SuiteContext->(Null->Void)->Dynamic>; + +/** + Callback for `before` / `after` / `beforeEach` / `afterEach` hooks. +**/ +typedef HookCallback = Function; + +/** + Configuration options for a test or suite. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#testname-options-fn +**/ +typedef TestOptions = { + /** + If a number is provided, that many tests run asynchronously. + If `true`, all scheduled asynchronous tests run concurrently. + If `false`, only one test runs at a time. + Default: `false` (subtests inherit from parent when unspecified). + **/ + @:optional var concurrency:EitherType; + + /** + If truthy, the test is expected to fail. + A string is shown as the reason; a `RegExp` / function / object / `Error` + is matched like `Assert.throws`. Use `{ label, match }` for both. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#expecting-tests-to-fail + **/ + @:optional var expectFailure:EitherType>>>>; + + /** + If truthy, and the test context is configured to run `only` tests, this test runs. + Otherwise it is skipped. Default: `false`. + **/ + @:optional var only:Bool; + + /** + Allows aborting an in-progress test. + **/ + @:optional var signal:AbortSignal; + + /** + If truthy, the test is skipped. A string is shown as the skip reason. Default: `false`. + **/ + @:optional var skip:EitherType; + + /** + If truthy, the test is marked `TODO`. A string is shown as the reason. Default: `false`. + **/ + @:optional var todo:EitherType; + + /** + Milliseconds after which the test fails. Default: `Infinity`. + **/ + @:optional var timeout:Float; + + /** + Number of assertions and subtests expected to run. Default: `undefined`. + **/ + @:optional var plan:Int; +} + +/** + Object form of `expectFailure` providing both a label and a matcher. +**/ +typedef ExpectFailureOptions = { + /** + Reason displayed in the test results. + **/ + @:optional var label:String; + + /** + Matcher for the thrown value (same forms as `Assert.throws`). + **/ + @:optional var match:EitherType>>; +} + +/** + Configuration options for hooks. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#beforefn-options +**/ +typedef HookOptions = { + /** + Allows aborting an in-progress hook. + **/ + @:optional var signal:AbortSignal; + + /** + Milliseconds after which the hook fails. Default: `Infinity`. + **/ + @:optional var timeout:Float; +} + +/** + Options for `TestContext.plan()`. +**/ +typedef PlanOptions = { + /** + If `true`, wait indefinitely for planned assertions/subtests. + If `false`, check immediately when the test function completes. + If a number, maximum wait time in milliseconds. Default: `false`. + **/ + @:optional var wait:EitherType; +} + +/** + Options for `TestContext.waitFor()`. +**/ +typedef WaitForOptions = { + /** + Milliseconds to wait after an unsuccessful `condition` before retrying. Default: `50`. + **/ + @:optional var interval:Float; + + /** + Poll timeout in milliseconds. Default: `1000`. + **/ + @:optional var timeout:Float; +} + +/** + Options for snapshot assertions on `TestContext.assert`. +**/ +typedef SnapshotAssertionOptions = { + /** + Serializers applied in order; final result is coerced to a string. + **/ + @:optional var serializers:ArrayDynamic>; +} + +/** + Configuration options for `Test.run()`. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#runoptions +**/ +typedef RunOptions = { + /** + Parallelism for test files. Number of processes, or `true`/`false`. Default: `false`. + **/ + @:optional var concurrency:EitherType; + + /** + Working directory used as the base path for resolving files. Default: `process.cwd()`. + **/ + @:optional var cwd:String; + + /** + List of files to run. Default: same as CLI. + **/ + @:optional var files:Array; + + /** + Exit the process once all known tests finished even if the event loop remains active. + Default: `false`. + **/ + @:optional var forceExit:Bool; + + /** + Glob patterns to match test files. Cannot be used with `files`. + **/ + @:optional var globPatterns:Array; + + /** + Inspector port for test child processes, or a function returning a port. + **/ + @:optional var inspectPort:EitherTypeInt>; + + /** + Test isolation: `'process'` (default) or `'none'`. + **/ + @:optional var isolation:String; + + /** + If truthy, only run tests with the `only` option set. + **/ + @:optional var only:Bool; + + /** + Setup listeners on the returned `TestsStream` before tests run. + **/ + @:optional var setup:TestsStream->Any; + + /** + CLI flags passed to the `node` executable when spawning subprocesses. + **/ + @:optional var execArgv:Array; + + /** + CLI flags passed to each test file when spawning subprocesses. + **/ + @:optional var argv:Array; + + /** + Allows aborting an in-progress test execution. + **/ + @:optional var signal:AbortSignal; + + /** + Only run tests whose names match these pattern(s). + **/ + @:optional var testNamePatterns:EitherType>>>; + + /** + Skip tests whose names match these pattern(s). + **/ + @:optional var testSkipPatterns:EitherType>>>; + + /** + Fail the run after this many milliseconds. Default: `Infinity`. + **/ + @:optional var timeout:Float; + + /** + Whether to run in watch mode. Default: `false`. + **/ + @:optional var watch:Bool; + + /** + Shard configuration for horizontal parallelization. + **/ + @:optional var shard:RunShardOptions; + + /** + Randomize execution order for test files and queued tests. Default: `false`. + **/ + @:optional var randomize:Bool; + + /** + Seed for deterministic randomization (`0`..`4294967295`). Enables randomization. + **/ + @:optional var randomSeed:Int; + + /** + File path where the runner stores state for `--test-rerun-failures`. + **/ + @:optional var rerunFailuresFilePath:String; + + /** + Enable code coverage collection. Default: `false`. + **/ + @:optional var coverage:Bool; + + /** + Exclude files from coverage via glob(s). + **/ + @:optional var coverageExcludeGlobs:EitherType>; + + /** + Include files in coverage via glob(s). + **/ + @:optional var coverageIncludeGlobs:EitherType>; + + /** + Require a minimum percent of covered lines. Default: `0`. + **/ + @:optional var lineCoverage:Float; + + /** + Require a minimum percent of covered branches. Default: `0`. + **/ + @:optional var branchCoverage:Float; + + /** + Require a minimum percent of covered functions. Default: `0`. + **/ + @:optional var functionCoverage:Float; + + /** + Environment variables for test processes (not merged with `process.env`). + Incompatible with `isolation: 'none'`. + **/ + @:optional var env:DynamicAccess; +} + +/** + Shard selection for `RunOptions.shard`. +**/ +typedef RunShardOptions = { + /** + Shard index between `1` and `total` (required). + **/ + var index:Int; + + /** + Total number of shards (required). + **/ + var total:Int; +} + +/** + Module-level snapshot configuration (`Test.snapshot`). +**/ +typedef Snapshot = { + /** + Customize the default serializers used by snapshot tests. + Default serialization is `JSON.stringify(value, null, 2)`. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#snapshotsetdefaultsnapshotserializersserializers + **/ + function setDefaultSnapshotSerializers(serializers:ArrayDynamic>):Void; + + /** + Customize where snapshot files are written. + `fn` receives the test file path (or `undefined` in the REPL) and must return a path string. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#snapshotsetresolvesnapshotpathfn + **/ + function setResolveSnapshotPath(fn:Null->String):Void; +} + +/** + Module-level assert configuration (`Test.assert`). + + Does not re-export `node:assert`; see `js.node.Assert` for assertions. + `TestContext.assert` exposes assert methods bound to the test context for planning. +**/ +typedef TestAssert = { + /** + Defines a new assertion function available on `TestContext.assert`. + Overwrites an existing assertion with the same name. + + @see https://nodejs.org/docs/latest-v24.x/api/test.html#assertregistername-fn + **/ + function register(name:String, fn:Function):Void; +} diff --git a/src/js/node/Timers.hx b/src/js/node/Timers.hx index 4ef3da7e..697678e5 100644 --- a/src/js/node/Timers.hx +++ b/src/js/node/Timers.hx @@ -135,4 +135,11 @@ extern class Timeout { Creating too many of these can adversely impact performance of the Node.js application. **/ function unref():Timeout; + + /** + Cancels the timeout. + + Stability: 3 - Legacy: Use `clearTimeout()` instead. + **/ + function close():Timeout; } diff --git a/src/js/node/TimersPromises.hx b/src/js/node/TimersPromises.hx new file mode 100644 index 00000000..010e4327 --- /dev/null +++ b/src/js/node/TimersPromises.hx @@ -0,0 +1,103 @@ +/* + * Copyright (C)2014-2020 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package js.node; + +import js.lib.Promise; +import js.node.web.AbortSignal; + +/** + The `timers/promises` API provides an alternative set of timer functions that return `Promise` objects. + + @see https://nodejs.org/api/timers.html#timers-promises-api +**/ +@:jsRequire("timers/promises") +extern class TimersPromises { + /** + Returns a Promise that is fulfilled with `value` after `delay` milliseconds. + **/ + @:overload(function():Promise {}) + @:overload(function(delay:Int):Promise {}) + @:overload(function(delay:Int, value:T):Promise {}) + static function setTimeout(delay:Int, value:T, options:TimersPromisesOptions):Promise; + + /** + Returns a Promise that is fulfilled with `value` in the next iteration of the event loop + (after I/O events' callbacks). + **/ + @:overload(function():Promise {}) + @:overload(function(value:T):Promise {}) + static function setImmediate(value:T, options:TimersPromisesOptions):Promise; + + /** + Returns an async iterator that generates values in an interval of `delay` ms. + **/ + @:overload(function():TimersPromisesAsyncIterator {}) + @:overload(function(delay:Int):TimersPromisesAsyncIterator {}) + @:overload(function(delay:Int, value:T):TimersPromisesAsyncIterator {}) + static function setInterval(delay:Int, value:T, options:TimersPromisesOptions):TimersPromisesAsyncIterator; + + /** + Experimental Scheduling APIs draft helpers (`scheduler.wait` / `scheduler.yield`). + **/ + static var scheduler(default, null):TimersPromisesScheduler; +} + +/** + Options shared by `TimersPromises` scheduling methods. +**/ +typedef TimersPromisesOptions = { + /** + Set to `false` so the scheduled timer does not require the event loop to remain active. + Default: `true`. + **/ + @:optional var ref:Bool; + + /** + An optional `AbortSignal` that can be used to cancel the scheduled timer. + **/ + @:optional var signal:AbortSignal; +} + +/** + Minimal async iterator surface used by `setInterval` (for `for await...of`). +**/ +typedef TimersPromisesAsyncIterator = { + function next():Promise<{done:Bool, ?value:T}>; +} + +/** + Experimental `scheduler` helpers from `timers/promises`. +**/ +typedef TimersPromisesScheduler = { + /** + Wait `delay` milliseconds before resolving. + Equivalent to `setTimeout(delay, undefined, options)`. + **/ + function wait(delay:Int, ?options:TimersPromisesOptions):Promise; + + /** + Yield to the event loop. + Equivalent to `setImmediate()` with no arguments. + **/ + function yield():Promise; +} diff --git a/src/js/node/Tls.hx b/src/js/node/Tls.hx index a1111062..b3f85597 100644 --- a/src/js/node/Tls.hx +++ b/src/js/node/Tls.hx @@ -22,17 +22,14 @@ package js.node; +import haxe.DynamicAccess; import haxe.extern.EitherType; import js.node.Buffer; import js.node.tls.SecureContext; import js.node.tls.SecurePair; import js.node.tls.Server; import js.node.tls.TLSSocket; -#if haxe4 import js.lib.Error; -#else -import js.Error; -#end typedef TlsOptionsBase = { /** @@ -44,8 +41,17 @@ typedef TlsOptionsBase = { /** possible NPN protocols. (Protocols should be ordered by their priority). + + @deprecated Use `ALPNProtocols` instead. **/ + @:deprecated("Use ALPNProtocols instead") @:optional var NPNProtocols:EitherType, Buffer>; + + /** + An array of strings or a Buffer naming possible ALPN protocols. + (Protocols should be ordered by their priority.) + **/ + @:optional var ALPNProtocols:EitherType>, Buffer>; } typedef TlsServerOptionsBase = { @@ -65,7 +71,7 @@ typedef TlsServerOptionsBase = { (You can use tls.createSecureContext(...) to get proper `SecureContext`). If `SNICallback` wasn't provided - default callback with high-level API will be used. **/ - @:optional var SNICallback:#if (haxe_ver >= 4)(servername:String, cb:(Error->SecureContext)) -> Void #else String->(Error->SecureContext)->Void #end; + @:optional var SNICallback:(servername:String, cb:(Null, SecureContext) -> Void) -> Void; } typedef TlsClientOptionsBase = { @@ -111,6 +117,21 @@ typedef TlsCreateServerOptions = { NOTE: Automatically shared between cluster module workers. **/ @:optional var ticketKeys:Buffer; + + /** + If true, `tls.TLSSocket.enableTrace()` is called on new connections. + + @see https://nodejs.org/api/tls.html#tlscreateserveroptions-secureconnectionlistener + **/ + @:optional var enableTrace:Bool; + + /** + If set, called when a client opens a connection using the ALPN extension. + Return one of the client's protocols, or `undefined` to reject. + + @see https://nodejs.org/api/tls.html#tlscreateserveroptions-secureconnectionlistener + **/ + @:optional var ALPNCallback:(arg:{servername:String, protocols:Array}) -> Null; } typedef TlsConnectOptions = { @@ -149,8 +170,39 @@ typedef TlsConnectOptions = { An override for checking server's hostname against the certificate. Should return an error if verification fails. Return `js.Lib.undefined` if passing. **/ - @:optional var checkServerIdentity:String -> {}->Dynamic; // TODO: peer cerficicate structure + @:optional var checkServerIdentity:(servername:String, cert:PeerCertificate) -> Null; +} +/** + Common fields of the certificate object returned by `TLSSocket.getPeerCertificate`. + + // TODO(section-3): expand full PeerCertificate / DetailedPeerCertificate field set from OpenSSL +**/ +typedef PeerCertificate = { + @:optional var subject:CertificateSubject; + @:optional var issuer:CertificateSubject; + @:optional var subjectaltname:String; + @:optional var infoAccess:haxe.DynamicAccess>; + @:optional var modulus:String; + @:optional var exponent:String; + @:optional var valid_from:String; + @:optional var valid_to:String; + @:optional var fingerprint:String; + @:optional var fingerprint256:String; + @:optional var fingerprint512:String; + @:optional var serialNumber:String; + @:optional var raw:Buffer; + // present when detailed=true + @:optional var issuerCertificate:PeerCertificate; +} + +typedef CertificateSubject = { + @:optional var C:String; + @:optional var ST:String; + @:optional var L:String; + @:optional var O:String; + @:optional var OU:String; + @:optional var CN:String; } /** @@ -169,6 +221,38 @@ extern class Tls { **/ static var CLIENT_RENEG_WINDOW:Int; + /** + The default value of the `ciphers` option of `Tls.createSecureContext`. + It can be assigned any of the supported OpenSSL ciphers. + **/ + static var DEFAULT_CIPHERS:String; + + /** + The default named curve to use for ECDH key agreement in a tls server. + The default value is `'auto'`. + **/ + static var DEFAULT_ECDH_CURVE:String; + + /** + The default value of the `maxVersion` option of `Tls.createSecureContext`. + It can be assigned any of the supported TLS protocol versions: + `'TLSv1.3'`, `'TLSv1.2'`, `'TLSv1.1'`, or `'TLSv1'`. + **/ + static var DEFAULT_MAX_VERSION:String; + + /** + The default value of the `minVersion` option of `Tls.createSecureContext`. + It can be assigned any of the supported TLS protocol versions: + `'TLSv1.3'`, `'TLSv1.2'`, `'TLSv1.1'`, or `'TLSv1'`. + **/ + static var DEFAULT_MIN_VERSION:String; + + /** + An immutable array of strings representing the root certificates (in PEM format) + from the bundled Mozilla CA store as supplied by the current Node.js version. + **/ + static var rootCertificates(default, null):Array; + /** Size of slab buffer used by all tls servers and clients. Default: 10 * 1024 * 1024. @@ -176,11 +260,45 @@ extern class Tls { **/ static var SLAB_BUFFER_SIZE:Int; + /** + Returns an array containing the CA certificates from various sources, depending on `type`. + + Valid values for `type` are `'default'`, `'system'`, `'bundled'` and `'extra'`. + Default: `'default'`. + + @see https://nodejs.org/api/tls.html#tlsgetcacertificatestype + **/ + static function getCACertificates(?type:String):Array; + + /** + Sets the default CA certificates used by Node.js TLS clients. + If the provided certificates are parsed successfully, they become the default CA + certificate list returned by `getCACertificates()` and used by subsequent TLS + connections that don't specify their own CA certificates. + + @see https://nodejs.org/api/tls.html#tlssetdefaultcacertificatescerts + **/ + static function setDefaultCACertificates(certs:Array>):Void; + /** Returns an array with the names of the supported SSL ciphers. **/ static function getCiphers():Array; + /** + Verifies the certificate `cert` is issued to `hostname`. + + Returns an `Error` object on failure, or `undefined` on success. + **/ + static function checkServerIdentity(hostname:String, cert:PeerCertificate):Null; + + /** + Converts the given ALPN protocols list into wire-format expected by OpenSSL. + + @see https://nodejs.org/api/tls.html#tlsconvertalpnprotocolsprotocols-out + **/ + static function convertALPNProtocols(protocols:EitherType>, Buffer>, out:{}):Void; + /** Creates a new `Server`. The `connectionListener` argument is automatically set as a listener for the 'secureConnection' event. @@ -195,6 +313,7 @@ extern class Tls { @:overload(function(port:Int, options:TlsConnectOptions, ?callback:Void->Void):TLSSocket {}) @:overload(function(port:Int, host:String, ?callback:Void->Void):TLSSocket {}) @:overload(function(port:Int, host:String, options:TlsConnectOptions, ?callback:Void->Void):TLSSocket {}) + @:overload(function(path:String, ?options:TlsConnectOptions, ?callback:Void->Void):TLSSocket {}) static function connect(options:TlsConnectOptions, ?callback:Void->Void):TLSSocket; /** @@ -208,5 +327,6 @@ extern class Tls { Generally the encrypted one is piped to/from an incoming encrypted data stream, and the cleartext one is used as a replacement for the initial encrypted stream. **/ + @:deprecated("Use Tls.TLSSocket instead") static function createSecurePair(?context:SecureContext, ?isServer:Bool, ?requestCert:Bool, ?rejectUnauthorized:Bool):SecurePair; } diff --git a/src/js/node/TraceEvents.hx b/src/js/node/TraceEvents.hx new file mode 100644 index 00000000..ff54bfd3 --- /dev/null +++ b/src/js/node/TraceEvents.hx @@ -0,0 +1,60 @@ +/* + * Copyright (C)2014-2020 Haxe Foundation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +package js.node; + +import js.node.trace_events.Tracing; + +/** + The `node:trace_events` module centralizes tracing information generated by + V8, Node.js core, and userspace code. + + Stability: 1 - Experimental. + + @see https://nodejs.org/docs/latest-v24.x/api/tracing.html +**/ +@:jsRequire("node:trace_events") +extern class TraceEvents { + /** + Creates and returns a `Tracing` object for the given set of `categories`. + + @see https://nodejs.org/docs/latest-v24.x/api/tracing.html#trace_eventscreatetracingoptions + **/ + static function createTracing(options:CreateTracingOptions):Tracing; + + /** + Returns a comma-separated list of all currently-enabled trace event categories. + + @see https://nodejs.org/docs/latest-v24.x/api/tracing.html#trace_eventsgetenabledcategories + **/ + static function getEnabledCategories():Null; +} + +/** + Options for `TraceEvents.createTracing`. +**/ +typedef CreateTracingOptions = { + /** + An array of trace category names. + **/ + var categories:Array; +} diff --git a/src/js/node/Url.hx b/src/js/node/Url.hx index d0f10333..03e2a31f 100644 --- a/src/js/node/Url.hx +++ b/src/js/node/Url.hx @@ -22,6 +22,8 @@ package js.node; +import haxe.extern.EitherType; +import js.node.Buffer; import js.node.url.URL; /** @@ -39,16 +41,24 @@ extern class Url { /** Returns the Unicode serialization of the `domain`. If `domain` is an invalid domain, the empty string is returned. - It performs the inverse operation to `url.dmainToASCII()`. + It performs the inverse operation to `url.domainToASCII()`. **/ static function domainToUnicode(domain:String):String; /** This function ensures the correct decodings of percent-encoded characters as well as ensuring a cross-platform valid absolute path string. **/ + @:overload(function(url:String, ?options:FileUrlToPathOptions):String {}) + @:overload(function(url:URL, ?options:FileUrlToPathOptions):String {}) @:overload(function(url:String):String {}) static function fileURLToPath(url:URL):String; + /** + Like `fileURLToPath` but returns a `Buffer` containing the path. + **/ + @:overload(function(url:String, ?options:FileUrlToPathOptions):Buffer {}) + static function fileURLToPathBuffer(url:URL, ?options:FileUrlToPathOptions):Buffer; + /** Returns a customizable serialization of a URL `String` representation of a [WHATWG URL](https://nodejs.org/api/url.html#url_the_whatwg_url_api) object. @@ -66,7 +76,7 @@ extern class Url { This function ensures that `path` is resolved absolutely, and that the URL control characters are correctly encoded when converting into a File URL. **/ - static function pathToFileURL(path:String):URL; + static function pathToFileURL(path:String, ?options:PathToFileUrlOptions):URL; /** Takes a URL string, parses it, and returns a URL object. @@ -79,7 +89,7 @@ extern class Url { For instance, given `//foo/bar`, the result would be `{host: 'foo', pathname: '/bar'}` rather than `{pathname: '//foo/bar'}`. Defaults to false. **/ - @:deprecated + @:deprecated("Use js.node.url.URL instead") static function parse(urlString:String, ?parseQueryString:Bool, ?slashesDenoteHost:Bool):UrlObject; /** @@ -93,8 +103,76 @@ extern class Url { resolve('http://example.com/one', '/two') // 'http://example.com/two' ``` **/ - @:deprecated + @:deprecated("Use js.node.url.URL instead") static function resolve(from:String, to:String):String; + + /** + Deprecated legacy helper similar to `resolve`, operating on URL objects. + + @see https://nodejs.org/api/url.html + **/ + @:deprecated("Use js.node.url.URL instead") + static function resolveObject(source:EitherType, relative:EitherType):UrlObject; + + /** + This utility function converts a URL object into an ordinary options object as expected by the `http.request()` and `https.request()` APIs. + + @see https://nodejs.org/api/url.html#urlurltohttpoptionsurl + **/ + static function urlToHttpOptions(url:URL):UrlHttpOptions; +} + +/** + Options object returned by `Url.urlToHttpOptions`, compatible with `http.request` / `https.request`. + + @see https://nodejs.org/api/url.html#urlurltohttpoptionsurl +**/ +typedef UrlHttpOptions = { + /** + Protocol to use. + **/ + @:optional var protocol:String; + + /** + A domain name or IP address of the server to issue the request to. + **/ + @:optional var hostname:String; + + /** + The fragment portion of the URL. + **/ + @:optional var hash:String; + + /** + The serialized query portion of the URL. + **/ + @:optional var search:String; + + /** + The path portion of the URL. + **/ + @:optional var pathname:String; + + /** + Request path. Should include query string if any. + E.g. `'/index.html?page=12'`. + **/ + @:optional var path:String; + + /** + The serialized URL. + **/ + @:optional var href:String; + + /** + Port of remote server. + **/ + @:optional var port:EitherType; + + /** + Basic authentication i.e. `'user:password'` to compute an Authorization header. + **/ + @:optional var auth:String; } typedef UrlFormatOptions = { @@ -131,7 +209,7 @@ typedef UrlFormatOptions = { Parsed URL objects have some or all of the following fields, depending on whether or not they exist in the URL string. Any parts that are not in the URL string will not be in the parsed object. **/ -@:deprecated +@:deprecated("Use js.node.url.URL instead") typedef UrlObject = { /** The full URL string that was parsed with both the `protocol` and `host` components converted to lower-case. @@ -237,3 +315,23 @@ typedef UrlObject = { **/ @:optional var hash:String; } + +/** + Options for `Url.fileURLToPath` / `fileURLToPathBuffer`. +**/ +typedef FileUrlToPathOptions = { + /** + `true` if the path should retain Windows-style separators. + **/ + @:optional var windows:Bool; +} + +/** + Options for `Url.pathToFileURL`. +**/ +typedef PathToFileUrlOptions = { + /** + `true` if the path is a Windows path. + **/ + @:optional var windows:Bool; +} diff --git a/src/js/node/Util.hx b/src/js/node/Util.hx index 8597873e..5cbab91b 100644 --- a/src/js/node/Util.hx +++ b/src/js/node/Util.hx @@ -23,17 +23,16 @@ package js.node; import haxe.Constraints.Function; +import haxe.DynamicAccess; import haxe.extern.EitherType; import haxe.extern.Rest; -import js.node.stream.Readable; -import js.node.stream.Writable; -#if haxe4 import js.lib.Error; +import js.lib.Map; import js.lib.Promise; -#else -import js.Error; -import js.Promise; -#end +import js.node.stream.Readable; +import js.node.stream.Writable; +import js.node.web.AbortController; +import js.node.web.AbortSignal; /** The `util` module is primarily designed to support the needs of Node.js' own internal APIs. @@ -48,7 +47,8 @@ extern class Util { @see https://nodejs.org/api/util.html#util_util_callbackify_original **/ - static function callbackify(original:Function, args:Rest):Null->Null->Void; + // TODO(section-4): tighten callbackify return/arg types beyond Function + static function callbackify(original:Function):Function; /** The `util.debuglog()` method is used to create a function that conditionally writes debug messages to `stderr` @@ -56,15 +56,15 @@ extern class Util { @see https://nodejs.org/api/util.html#util_util_debuglog_section **/ - static function debuglog(section:String):Rest->Void; + static function debuglog(section:String):Rest->Void; /** The `util.deprecate()` method wraps `fn` (which may be a function or class) in such a way that it is marked - asdeprecated. + as deprecated. @see https://nodejs.org/api/util.html#util_util_deprecate_fn_msg_code **/ - static function deprecate(fun:T, msg:String, ?code:String):T; + static function deprecate(fun:T, msg:String, ?code:String):T; /** The `util.format()` method returns a formatted string using the first argument as a `printf`-like format string @@ -72,8 +72,8 @@ extern class Util { @see https://nodejs.org/api/util.html#util_util_format_format_args **/ - @:overload(function(args:Rest):String {}) - static function format(format:String, args:Rest):String; + @:overload(function(args:Rest):String {}) + static function format(format:String, args:Rest):String; /** This function is identical to `util.format()`, except in that it takes an `inspectOptions` argument which @@ -81,8 +81,8 @@ extern class Util { @see https://nodejs.org/api/util.html#util_util_formatwithoptions_inspectoptions_format_args **/ - @:overload(function(inspectOptions:InspectOptions, args:Rest):String {}) - static function formatWithOptions(inspectOptions:InspectOptions, format:String, args:Rest):String; + @:overload(function(inspectOptions:InspectOptions, args:Rest):String {}) + static function formatWithOptions(inspectOptions:InspectOptions, format:String, args:Rest):String; /** Returns the string name for a numeric error code that comes from a Node.js API. @@ -91,12 +91,27 @@ extern class Util { **/ static function getSystemErrorName(err:Int):String; + /** + Returns the system error message associated with a numeric error code. + + @see https://nodejs.org/api/util.html#utilgetsystemerrormessageerr + **/ + static function getSystemErrorMessage(err:Int):String; + + /** + Returns a Map of all system error codes available from the Node.js API. + Map values are `[name, message]` string pairs. + + @see https://nodejs.org/api/util.html#utilgetsystemerrormap + **/ + static function getSystemErrorMap():Map>; + /** Inherit the prototype methods from one `constructor` into another. @see https://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor **/ - @:deprecated + @:deprecated("Use class extends instead") static function inherits(constructor:Class, superConstructor:Class):Void; /** @@ -104,15 +119,15 @@ extern class Util { @see https://nodejs.org/api/util.html#util_util_inspect_object_options **/ - @:overload(function(object:Dynamic, ?showHidden:Bool, ?depth:Int, ?colors:Bool):String {}) - static function inspect(object:Dynamic, ?options:InspectOptions):String; + @:overload(function(object:Any, ?showHidden:Bool, ?depth:Int, ?colors:Bool):String {}) + static function inspect(object:Any, ?options:InspectOptions):String; /** Returns `true` if there is deep strict equality between `val1` and `val2`. @see https://nodejs.org/api/util.html#util_util_isdeepstrictequal_val1_val2 **/ - static function isDeepStrictEqual(val1:Dynamic, val2:Dynamic):Bool; + static function isDeepStrictEqual(val1:Any, val2:Any):Bool; /** Takes a function following the common error-first callback style, i.e. taking an `(err, value) => ...` callback @@ -120,7 +135,100 @@ extern class Util { @see https://nodejs.org/api/util.html#util_util_promisify_original **/ - static function promisify(original:Function):Rest->Promise; + // TODO(section-4): tighten promisify generic result typing + static function promisify(original:Function):Rest->Promise; + + /** + Parses command-line `args` into an options object according to `config`. + + // TODO(section-4): generic ParseArgsConfig / ParsedResults refinement + + @see https://nodejs.org/api/util.html#utilparseargsconfig + **/ + static function parseArgs(?config:ParseArgsConfig):ParseArgsResult; + + /** + Parses the raw contents of an `.env` file. + + @see https://nodejs.org/api/util.html#utilparseenvcontent + **/ + static function parseEnv(content:String):DynamicAccess; + + /** + Removes any ANSI escape codes from the specified string. + + @see https://nodejs.org/api/util.html#utilstripvtcontrolcharactersstr + **/ + static function stripVTControlCharacters(str:String):String; + + /** + Returns a formatted text considering the `format` passed for printing in a terminal. + + @see https://nodejs.org/api/util.html#utilstyletextformat-text-options + **/ + static function styleText(format:EitherType>, text:String, ?options:StyleTextOptions):String; + + /** + Returns the `string` after replacing any unpaired surrogate code units with U+FFFD. + + @see https://nodejs.org/api/util.html#utiltousvstringstring + **/ + static function toUSVString(string:String):String; + + /** + Returns an `AbortController` that can be transferred to a Worker via `postMessage`. + + @see https://nodejs.org/api/util.html#utiltransferableabortcontroller + **/ + static function transferableAbortController():AbortController; + + /** + Marks an existing `AbortSignal` as transferable so it can be sent to a Worker. + + @see https://nodejs.org/api/util.html#utiltransferableabortsignalsignal + **/ + static function transferableAbortSignal(signal:AbortSignal):AbortSignal; + + /** + Listens to abort on `signal` and resource lifetime; resolves when aborted (or resource GC'd). + + @see https://nodejs.org/api/util.html#utilabortedsignal-resource + **/ + static function aborted(signal:AbortSignal, resource:Any):Promise; + + /** + Compares `actual` and `expected` and returns the differences as an array of diff entries. + + @see https://nodejs.org/api/util.html#utildiffactual-expected + **/ + static function diff(actual:EitherType>, expected:EitherType>):Array; + + /** + Returns an array of call site objects from the current stack. + + @see https://nodejs.org/api/util.html#utilgetcallsitesframecount-options + **/ + @:overload(function(?options:GetCallSitesOptions):Array {}) + static function getCallSites(?frameCount:Int, ?options:GetCallSitesOptions):Array; + + /** + Legacy alias of `getCallSites`. + + @see https://nodejs.org/api/util.html#utilgetcallsitesframecount-options + **/ + @:deprecated("Use Util.getCallSites instead") + @:overload(function(?options:GetCallSitesOptions):Array {}) + static function getCallSite(?frameCount:Int, ?options:GetCallSitesOptions):Array; + + /** + Converts a POSIX signal name (e.g. `'SIGTERM'`) to the corresponding process exit code. + **/ + static function convertProcessSignalToExitCode(signal:String):Int; + + /** + Enables or disables printing a stack trace when Node.js receives `SIGINT`. + **/ + static function setTraceSigInt(enable:Bool):Void; /** Deprecated predecessor of `Console.error`. @@ -132,115 +240,115 @@ extern class Util { Deprecated predecessor of console.error. **/ @:deprecated("Use js.Node.console.error instead") - static function error(args:Rest):Void; + static function error(args:Rest):Void; /** Returns true if the given "object" is an Array. false otherwise. **/ - @:deprecated - static function isArray(object:Dynamic):Bool; + @:deprecated("Use Std.isOfType(value, Array) instead") + static function isArray(object:Any):Bool; /** Returns true if the given "object" is a Bool. false otherwise. **/ - @:deprecated - static function isBoolean(object:Dynamic):Bool; + @:deprecated("Use (value is Bool) instead") + static function isBoolean(object:Any):Bool; /** Returns true if the given "object" is a Buffer. false otherwise. **/ - @:deprecated - static function isBuffer(object:Dynamic):Bool; + @:deprecated("Use Buffer.isBuffer instead") + static function isBuffer(object:Any):Bool; /** Returns true if the given "object" is a Date. false otherwise. **/ - @:deprecated - static function isDate(object:Dynamic):Bool; + @:deprecated("Use js.node.util.Types.isDate instead") + static function isDate(object:Any):Bool; /** Returns true if the given "object" is an Error. false otherwise. **/ - @:deprecated - static function isError(object:Dynamic):Bool; + @:deprecated("Use js.node.util.Types.isNativeError instead") + static function isError(object:Any):Bool; /** Returns true if the given "object" is a Function. false otherwise. **/ - @:deprecated - static function isFunction(object:Dynamic):Bool; + @:deprecated("Use Reflect.isFunction instead") + static function isFunction(object:Any):Bool; /** Returns true if the given "object" is strictly null. false otherwise. **/ - @:deprecated - static function isNull(object:Dynamic):Bool; + @:deprecated("Use (value == null) instead") + static function isNull(object:Any):Bool; /** Returns true if the given "object" is null or undefined. false otherwise. **/ - @:deprecated - static function isNullOrUndefined(object:Dynamic):Bool; + @:deprecated("Use (value == null) instead") + static function isNullOrUndefined(object:Any):Bool; /** Returns true if the given "object" is a Float. false otherwise. **/ - @:deprecated - static function isNumber(object:Dynamic):Bool; + @:deprecated("Use (value is Float) instead") + static function isNumber(object:Any):Bool; /** Returns true if the given "object" is strictly an Object and not a Function. false otherwise. **/ - @:deprecated - static function isObject(object:Dynamic):Bool; + @:deprecated("Use value != null && js.Syntax.typeof(value) == \"object\" instead") + static function isObject(object:Any):Bool; /** Returns true if the given "object" is a primitive type. false otherwise. **/ - @:deprecated - static function isPrimitive(object:Dynamic):Bool; + @:deprecated("Use (js.Syntax.typeof(value) != \"object\" && js.Syntax.typeof(value) != \"function\") || value == null instead") + static function isPrimitive(object:Any):Bool; /** Returns true if the given "object" is a RegExp. false otherwise. **/ - @:deprecated - static function isRegExp(object:Dynamic):Bool; + @:deprecated("Use js.node.util.Types.isRegExp instead") + static function isRegExp(object:Any):Bool; /** Returns true if the given "object" is a String. false otherwise. **/ - @:deprecated - static function isString(object:Dynamic):Bool; + @:deprecated("Use (value is String) instead") + static function isString(object:Any):Bool; /** Returns true if the given "object" is a Symbol. false otherwise. **/ - @:deprecated - static function isSymbol(object:Dynamic):Bool; + @:deprecated("Use js.Syntax.typeof(value) == \"symbol\" instead") + static function isSymbol(object:Any):Bool; /** Returns true if the given "object" is undefined. false otherwise. **/ - @:deprecated - static function isUndefined(object:Dynamic):Bool; + @:deprecated("Use js.Syntax.typeof(value) == \"undefined\" instead") + static function isUndefined(object:Any):Bool; /** Output with timestamp on stdout. **/ - @:deprecated - static function log(args:Rest):Void; + @:deprecated("Use js.Node.console.log instead") + static function log(args:Rest):Void; /** Deprecated predecessor of console.log. **/ @:deprecated("Use js.Node.console.log instead") - static function print(args:Rest):Void; + static function print(args:Rest):Void; /** Deprecated predecessor of console.log. **/ @:deprecated("Use js.Node.console.log instead") - static function puts(args:Rest):Void; + static function puts(args:Rest):Void; /** Deprecated predecessor of stream.pipe(). @@ -338,7 +446,7 @@ typedef InspectOptions = { If set to `true` the default sort is used. If set to a function, it is used as a compare function. **/ - @:optional var sorted:EitherTypeDynamic->Int>; + @:optional var sorted:EitherTypeAny->Int>; /** If set to `true`, getters are inspected. @@ -350,3 +458,75 @@ typedef InspectOptions = { **/ @:optional var getters:EitherType; } + +/** + Options object used by `Util.styleText`. +**/ +typedef StyleTextOptions = { + /** + A stream that will be validated if it can be colored. + + Default: `process.stdout`. + **/ + @:optional var stream:Any; + + /** + Value indicating whether `stream` is checked to see if it can handle colors. + + Default: `true`. + **/ + @:optional var validateStream:Bool; +} + +/** + Configuration for `Util.parseArgs`. +**/ +typedef ParseArgsConfig = { + @:optional var args:Array; + @:optional var options:DynamicAccess; + @:optional var strict:Bool; + @:optional var allowPositionals:Bool; + @:optional var allowNegative:Bool; + @:optional var tokens:Bool; +} + +/** + Descriptor for a single `parseArgs` option. +**/ +typedef ParseArgsOptionDescriptor = { + @:optional var type:String; + @:optional var multiple:Bool; + @:optional var short:String; + @:optional @:native("default") var defaultValue:Any; +} + +/** + Result of `Util.parseArgs`. +**/ +typedef ParseArgsResult = { + var values:DynamicAccess; + var positionals:Array; + @:optional var tokens:Array; +} + +/** + A single entry from `Util.diff`. +**/ +typedef DiffEntry = Array>; + +/** + Options for `Util.getCallSites`. +**/ +typedef GetCallSitesOptions = { + @:optional var sourceMap:Bool; +} + +/** + A call site object returned by `Util.getCallSites`. +**/ +typedef CallSiteObject = { + var functionName:String; + var scriptName:String; + var lineNumber:Int; + var columnNumber:Int; +} diff --git a/src/js/node/V8.hx b/src/js/node/V8.hx index d6138c4b..1deb5211 100644 --- a/src/js/node/V8.hx +++ b/src/js/node/V8.hx @@ -22,43 +22,137 @@ package js.node; +import haxe.Constraints.Function; +import js.node.Buffer; +import js.node.stream.Readable.IReadable; + /** The v8 module exposes APIs that are specific to the version of V8 built into the Node.js binary. - Note: The APIs and implementation are subject to change at any time. + @see https://nodejs.org/docs/latest-v24.x/api/v8.html + + // TODO(section-5): expand Serializer/Deserializer/DefaultSerializer subclasses and CPU/Heap profile handles **/ @:jsRequire("v8") extern class V8 { + /** + Returns an integer representing a version tag derived from the V8 version, command-line flags, + and detected CPU features. This is useful for determining whether a `vm.Script` `cachedData` buffer + is compatible with this instance of V8. + **/ + static function cachedDataVersionTag():Int; + + /** + Returns an object with statistics about the V8 heap spaces. + **/ static function getHeapStatistics():V8HeapStatistics; /** Returns statistics about the V8 heap spaces, i.e. the segments which make up the V8 heap. - Neither the ordering of heap spaces, nor the availability of a heap space can be guaranteed - as the statistics are provided via the V8 `GetHeapSpaceStatistics` function and may change - from one V8 version to the next. **/ static function getHeapSpaceStatistics():Array; /** - This method can be used to programmatically set V8 command line flags. This method should be used with care. - Changing settings after the VM has started may result in unpredictable behavior, including crashes and data loss; - or it may simply do nothing. + Get statistics about code and its metadata in the heap, see V8 `GetHeapCodeAndMetadataStatistics`. + **/ + static function getHeapCodeStatistics():V8HeapCodeStatistics; - The V8 options available for a version of Node.js may be determined by running `node --v8-options`. + /** + Generates a snapshot of the current V8 heap and returns a Readable stream that may be used to + read the JSON serialized representation. + **/ + static function getHeapSnapshot(?options:V8HeapSnapshotOptions):IReadable; + + /** + Generates a snapshot of the current V8 heap and writes it to a JSON file. + Returns the filename where the snapshot was saved. + **/ + @:overload(function(?options:V8HeapSnapshotOptions):String {}) + static function writeHeapSnapshot(?filename:String, ?options:V8HeapSnapshotOptions):String; + + /** + This method can be used to programmatically set V8 command line flags. **/ static function setFlagsFromString(string:String):Void; + + /** + The `v8.stopCoverage()` method allows the user to stop collecting coverage, which was started by + `NODE_V8_COVERAGE`. While `NODE_V8_COVERAGE` can be used for collecting coverage for both + tests (via `node:test`) and application code, this method can be used to stop collecting coverage + on either side of that boundary. + **/ + static function stopCoverage():Void; + + /** + The `v8.takeCoverage()` method allows the user to write the coverage started by `NODE_V8_COVERAGE` + to disk on demand. + **/ + static function takeCoverage():Void; + + /** + This API sets a limit for near-heap-limit callback invocations. + **/ + static function setHeapSnapshotNearHeapLimit(limit:Int):Void; + + /** + Uses a `DefaultSerializer` to serialize `value` into a buffer. + **/ + static function serialize(value:Dynamic):Buffer; + + /** + Uses a `DefaultDeserializer` with default options to read a JS value from a buffer. + **/ + static function deserialize(buffer:Buffer):Dynamic; + + /** + This API will find all objects corresponding to the constructor `ctor`. + **/ + static function queryObjects(ctor:Function, ?options:{format:String}):Dynamic; + + /** + Tracks `Promise` lifecycle callbacks. Prefer `async_hooks` / `diagnostics_channel` for most apps. + + // TODO(section-5): fully type promiseHooks createHook callbacks + **/ + static var promiseHooks(default, null):V8PromiseHooks; + + /** + Startup snapshot builder API (only meaningful when building a snapshot). + **/ + static var startupSnapshot(default, null):V8StartupSnapshot; + + /** + Starts a CPU profile and returns a handle that can be used to stop it. + // TODO(section-5): type CPUProfileHandle / SyncCPUProfileHandle / HeapProfileHandle + **/ + static function startCpuProfile():V8CpuProfileHandle; + + /** + Returns whether the string is stored in one-byte (Latin-1) representation in V8. + **/ + static function isStringOneByteRepresentation(content:String):Bool; } +// TODO(section-5): v8.Serializer / Deserializer / DefaultSerializer / DefaultDeserializer / GCProfiler / getCppHeapStatistics + /** Object returned by `V8.getHeapStatistics` method. **/ typedef V8HeapStatistics = { - var total_heap_size:Int; - var total_heap_size_executable:Int; - var total_physical_size:Int; - var total_available_size:Int; - var used_heap_size:Int; - var heap_size_limit:Int; + var total_heap_size:Float; + var total_heap_size_executable:Float; + var total_physical_size:Float; + var total_available_size:Float; + var used_heap_size:Float; + var heap_size_limit:Float; + @:optional var malloced_memory:Float; + @:optional var peak_malloced_memory:Float; + @:optional var does_zap_garbage:Int; + @:optional var number_of_native_contexts:Float; + @:optional var number_of_detached_contexts:Float; + @:optional var total_global_handles_size:Float; + @:optional var used_global_handles_size:Float; + @:optional var external_memory:Float; } /** @@ -66,8 +160,53 @@ typedef V8HeapStatistics = { **/ typedef V8HeapSpaceStatistics = { var space_name:String; - var space_size:Int; - var space_used_size:Int; - var space_available_size:Int; - var physical_space_size:Int; + var space_size:Float; + var space_used_size:Float; + var space_available_size:Float; + var physical_space_size:Float; +} + +/** + Object returned by `V8.getHeapCodeStatistics` method. +**/ +typedef V8HeapCodeStatistics = { + var code_and_metadata_size:Float; + var bytecode_and_metadata_size:Float; + var external_script_source_size:Float; + @:optional var cpu_profiler_metadata_size:Float; } + +typedef V8HeapSnapshotOptions = { + /** + If true, expose internals in the heap dump. Default: `false`. + **/ + @:optional var exposeInternals:Bool; + + /** + If true, expose numeric values in artificial fields. Default: `false`. + **/ + @:optional var exposeNumericValues:Bool; +} + +typedef V8PromiseHooks = { + function onInit(init:Function):Function; + function onSettled(settled:Function):Function; + function onBefore(before:Function):Function; + function onAfter(after:Function):Function; + function createHook(callbacks:{?init:Function, ?before:Function, ?after:Function, ?settled:Function}):Function; +} + +typedef V8StartupSnapshot = { + function addSerializeCallback(callback:Function, ?data:Dynamic):Void; + function addDeserializeCallback(callback:Function, ?data:Dynamic):Void; + function setDeserializeMainFunction(callback:Function, ?data:Dynamic):Void; + function isBuildingSnapshot():Bool; +} + +/** + Minimal handle returned by `V8.startCpuProfile`. +**/ +typedef V8CpuProfileHandle = { + function stop():String; +} + diff --git a/src/js/node/Vm.hx b/src/js/node/Vm.hx index 2c4bb9f0..b18186a9 100644 --- a/src/js/node/Vm.hx +++ b/src/js/node/Vm.hx @@ -22,10 +22,12 @@ package js.node; +import haxe.DynamicAccess; +import haxe.extern.EitherType; import js.node.vm.Script; /** - Options object used by Vm.run* methods. + Options object used by `Vm.run*` methods. **/ typedef VmRunOptions = { > ScriptOptions, @@ -33,8 +35,85 @@ typedef VmRunOptions = { } /** - Using this class JavaScript code can be compiled and - run immediately or compiled, saved, and run later. + Options for `Vm.createContext`. +**/ +typedef VmCreateContextOptions = { + /** + Human-readable name of the newly created context. Default: `'VM Context i'`, where `i` is an ascending + numerical index of the created context. + **/ + @:optional var name:String; + + /** + Origin corresponding to the newly created context for display purposes. The origin should be formatted like a + URL, but with only scheme, host, and port (if necessary). Default: `''`. + **/ + @:optional var origin:String; + + /** + If set to `true` any wrappers corresponding to `contextObject` properties may be invoked. Default: `false`. + **/ + @:optional var codeGeneration:VmCodeGenerationOptions; + + /** + If set to `afterEvaluate`, microtasks will be run immediately after evaluating code on the context + (before returning from e.g. `runInContext`). Default: `undefined`. + **/ + @:optional var microtaskMode:String; +} + +typedef VmCodeGenerationOptions = { + /** + If set to `false` any calls to `eval` or function constructors (`Function`, `GeneratorFunction`, etc) will throw + an `EvalError`. Default: `true`. + **/ + @:optional var strings:Bool; + + /** + If set to `false` any attempt to compile a WebAssembly module will throw a `WebAssembly.CompileError`. + Default: `true`. + **/ + @:optional var wasm:Bool; +} + +/** + Options for `Vm.compileFunction`. +**/ +typedef VmCompileFunctionOptions = { + > ScriptOptions, + /** + Provides an optional data with V8's code cache data for the supplied source. + **/ + @:optional var parsingContext:VmContext; + + /** + An array containing context extension objects. Modules and wrappers used in `code` will be available as if + they were referenced from these objects. + **/ + @:optional var contextExtensions:Array>; +} + +/** + Options for experimental `Vm.measureMemory`. +**/ +typedef VmMeasureMemoryOptions = { + /** + `'summary'` or `'detailed'`. Default: `'summary'`. + **/ + @:optional var mode:String; + + /** + `'self'` or `'all'`. Default: `'self'`. + **/ + @:optional var execution:String; +} + +/** + The `vm` module enables compiling and running code within V8 Virtual Machine contexts. + + @see https://nodejs.org/docs/latest-v24.x/api/vm.html + + // TODO(section-5): add vm.Module / SourceTextModule / SyntheticModule externs (large experimental surface) **/ @:jsRequire("vm") extern class Vm { @@ -42,68 +121,80 @@ extern class Vm { Compiles `code`, runs it and returns the result. Running code does not have access to local scope. - `filename` is optional, it's used only in stack traces. - - In case of syntax error in `code` emits the syntax error to stderr and throws an exception. + // TODO(section-5): Dynamic is intentional for arbitrary JS eval results; refine per-call sites when possible **/ - static function runInThisContext(code:String, ?options:VmRunOptions):Dynamic; + static function runInThisContext(code:String, ?options:EitherType):Dynamic; /** Compiles `code`, contextifies `sandbox` if passed or creates a new contextified sandbox if it's omitted, and then runs the code with the sandbox as the global object and returns the result. - - `runInNewContext` takes the same options as `runInThisContext`. - - Note that running untrusted code is a tricky business requiring great care. `runInNewContext` is quite useful, - but safely running untrusted code requires a separate process. **/ @:overload(function(code:String, ?sandbox:{}):Dynamic {}) static function runInNewContext(code:String, sandbox:{}, ?options:VmRunOptions):Dynamic; /** Compiles `code`, then runs it in `contextifiedSandbox` and returns the result. + **/ + static function runInContext(code:String, contextifiedSandbox:VmContext, ?options:EitherType):Dynamic; - Running code does not have access to local scope. The `contextifiedSandbox` object must have been previously - contextified via `createContext`; it will be used as the global object for code. - - `runInContext` takes the same options as `runInThisContext`. - - Note that running untrusted code is a tricky business requiring great care. `runInContext` is quite useful, - but safely running untrusted code requires a separate process. + /** + If given a sandbox object, will "contextify" that sandbox so that it can be used in calls to `runInContext` + or `Script.runInContext`. **/ - static function runInContext(code:String, contextifiedSandbox:VmContext, ?options:VmRunOptions):Dynamic; + @:overload(function():VmContext {}) + static function createContext(sandbox:T, ?options:VmCreateContextOptions):VmContext; /** + Returns whether or not a sandbox object has been contextified by calling `createContext` on it. + **/ + static function isContext(sandbox:{}):Bool; - If given a sandbox object, will "contextify" that sandbox so that it can be used in calls to `runInContext` or - `Script.runInContext`. Inside scripts run as such, sandbox will be the global object, retaining all its existing - properties but also having the built-in objects and functions any standard global object has. Outside of scripts - run by the vm module, sandbox will be unchanged. + /** + Compiles the given `code` into a function object that may use the provided `params` as formal parameters + and may use the objects in `options.contextExtensions` as its local scope. + **/ + static function compileFunction(code:String, ?params:Array, ?options:VmCompileFunctionOptions):haxe.Constraints.Function; - If not given a sandbox object, returns a new, empty contextified sandbox object you can use. + /** + Measure the known V8 heap memory attributed to this context / all contexts (experimental). - This function is useful for creating a sandbox that can be used to run multiple scripts, e.g. if you were - emulating a web browser it could be used to create a single sandbox representing a window's global object, - then run all