Sign in

    x

    Cross-platform IO abstraction for MoonBit with native wrappers and Node.js JS FFI implementations for process, fs, http, websocket, stdio, pipe, and sys.

    moonbit
    cross-platform
    io
    async
    nodejs
    process
    filesystem
    http
    websocket
    wasi
    Download zip
    Author
    Version
    0.1.1
    License
    Apache-2.0
    Last updated
    8 months ago
    Downloads
    203K

    #mizchi/x

    Cross-platform IO abstraction for MoonBit.

    Wraps moonbitlang/async (native) and provides JS FFI implementations so that the same API works across native, JS(Node.js), and WASM-GC(partially, it works on wasip1) targets.

    #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