Sign in

    x

    Node.js backend compatibility layer for moonbitlang/async in MoonBit, with native delegation and JS FFI implementations for process, fs, http, websocket, stdio, pipe, and sys.

    moonbit
    async
    backend
    compatibility
    nodejs
    process
    filesystem
    http
    websocket
    wasi
    Download zip
    Author
    Version
    0.1.7
    License
    Apache-2.0
    Last updated
    7 months ago
    Downloads
    203K

    #mizchi/x

    Node.js backend compatibility layer for moonbitlang/async in MoonBit.

    mizchi/x keeps native behavior by delegating to moonbitlang/async, and provides JS FFI implementations so the same async-style code can run on --target js (Node.js) with minimal changes.

    #Primary Goal

    • Run code written against moonbitlang/async on Node.js (--target js).
    • Keep native (--target native) semantics close by forwarding to upstream implementations.

    • mizchi/x: API is aligned with moonbitlang/async contracts (native-compatible surface).
    • mizchi/js/node: API is aligned with raw Node.js/JavaScript style APIs.

    #Dependencies

    DependencyVersion
    moonbitlang/async0.16.6
    moonbitlang/x0.4.40

    #Packages

    PackageDescription
    mizchi/x/processCommand execution (run, collect_output, collect_stdout, collect_stderr, collect_output_merged)
    mizchi/x/fsFile system operations (read_file, write_file, exists, mkdir, readdir, remove, rmdir)
    mizchi/x/httpHTTP client (get, post, put, get_stream, post_stream, put_stream)
    mizchi/x/websocketWebSocket client (connect, Conn::send_text, Conn::send_binary, Conn::recv, Conn::close)
    mizchi/x/stdioStandard I/O (stdin, stdout, stderr with @io.Reader/@io.Writer)
    mizchi/x/pipeIn-memory pipes (pipe() → PipeRead/PipeWrite with @io.Reader/@io.Writer)
    mizchi/x/sysEnvironment variables and CLI args (get_env_var, get_cli_args, exit)

    #Platform Support

    Packagenativejswasmwasm-gc
    processYesYesstubstub
    fsYesYesWASI P1stub
    httpYesYesstubstub
    websocketYesYesstubstub
    stdioYesYesstubstub
    pipeYesYesstubstub
    sysYesYesYesstub

    • Yes — Full implementation.
    • stub — Compiles but aborts at runtime with "not supported" message.
    • WASI P1 — Partial implementation using WASI Preview 1 syscalls.

    #Upstream Compatibility

    Compatibility with moonbitlang/async 0.16.6 / moonbitlang/x 0.4.40.

    The wrapper re-exports upstream types and APIs with matching signatures. On native, each function delegates directly to the upstream implementation. On JS, equivalent behavior is provided via extern "js" FFI (Node.js).

    #http (moonbitlang/async/http)

    Upstream tests: 20 | Covered: 2 | Skipped: 18

    Upstream testStatusNotes
    http requestCovered
    https requestCovered
    Other 18 testsSkipInternal parser/sender/proxy tests

    #websocket (moonbitlang/async/websocket)

    Upstream tests: 24 | Covered: 0 | Skipped: 24

    All upstream tests are internal (frame handling, ping/pong, UTF-8 validation) and not applicable to the wrapper's high-level API. The wrapper has 24 independent tests covering its own API.

    #pipe (moonbitlang/async/pipe)

    Upstream tests: 3 | Covered: 3 | Skipped: 0

    All upstream pipe tests are fully covered.

    #stdio (moonbitlang/async/stdio)

    Upstream tests: 3 | Covered: 0 | Skipped: 3

    All upstream tests require process piping/redirect features (@process.run with redirect options).

    #Quick Start

    just # check + test just fmt # format code just check # type check just test # run tests

    #Upstream test coverage by package

    Coverage is verified by scripts/sync-upstream-tests.sh, which extracts test names from the upstream packages and checks that each is either covered by a wrapper test or explicitly excluded in scripts/upstream-exclude.conf.

    #process (moonbitlang/async/process)

    Upstream tests: 28 | Covered: 10 | Skipped: 18

    Upstream testStatusNotes
    basic waitCovered
    basic_lsCovered
    collect_stdoutCovered
    collect_errorCovered
    collect_outputCovered
    collect_output_mergedCovered
    wait exitcodeCovered
    set cwdCovered
    set_envCovered
    set_env no inheritCovered
    basic_catSkipstdin pipe not yet exposed
    wait_pidSkipspawn_orphan not yet exposed
    cancel processSkipcancellation not yet exposed
    cancel process hardSkipcancellation not yet exposed
    cancel process timeoutSkipcancellation not yet exposed
    orphan processSkipspawn_orphan not yet exposed
    collect_output blockedSkipstdin param not yet exposed
    spawn_in_group waitSkipspawn not yet exposed
    spawn_in_group cancelSkipspawn not yet exposed
    Process::waitSkipProcess type not yet exposed
    Process::try_waitSkipProcess type not yet exposed
    Process:cancelSkipProcess type not yet exposed
    merge stdout and stderrSkipstdout/stderr redirect not yet exposed
    merge multipleSkipspawn + pipe redirect not yet exposed
    redirect to fileSkipfile redirect not yet exposed
    kill children on hard cancelSkiprequires custom test program + Windows
    do not kill orphan children on hard cancelSkiprequires custom test program + Windows
    windows command line arg escapeSkipWindows-specific

    #HTTP Server Operations (Node.js)

    #Reverse proxy / TLS termination

    When running @http.Server behind a reverse proxy (Nginx/Caddy/ALB), terminate TLS at the proxy and forward plain HTTP to the MoonBit process.

    • Enable proxy-aware client address resolution with:
      • @http.Server::new(..., trust_proxy=true)
    • Current JS behavior:
      • client_addr() uses x-forwarded-for (first hop) and x-forwarded-port
      • falls back to x-forwarded-host port when x-forwarded-port is absent

    Security note: set trust_proxy=true only when requests are guaranteed to come from trusted proxy hops.

    #SSE shutdown benchmark

    Run this JS-only benchmark test to check concurrent SSE shutdown behavior:

    moon test --target js src/http --filter 'bench(js): graceful close time under concurrent sse'

    The test prints a measurement line like:

    bench(js): sse_clients=24 graceful_close_ms=1507

    #k6 benchmark (default: JS vs Native)

    Use the dedicated benchmark server package and k6 scenarios. By default, this runs both js and native targets and prints a comparison summary.

    ./scripts/k6/run_http_bench.sh

    Environment variables:

    • PORT (default 18080)
    • VUS (default 128)
    • DURATION (default 20s)
    • BODY_SIZE (default 16384) for POST /consume
    • TARGETS (default "js native")
      • e.g. TARGETS=js to run JS only
      • e.g. TARGETS=native to run Native only

    Individual scenarios:

    BASE_URL=http://127.0.0.1:18080 k6 run scripts/k6/http_ping.js BASE_URL=http://127.0.0.1:18080 BODY_SIZE=16384 k6 run scripts/k6/http_consume.js BASE_URL=http://127.0.0.1:18080 BODY_SIZE=16384 k6 run scripts/k6/http_discard.js

    #License

    Apache-2.0