Sign in

    js

    bindings for js/node/browser/deno/cloudflare/react etc

    js
    node
    react
    preact
    dom
    async
    http
    cloudflare
    deno
    Download zip
    Author
    Version
    0.7.0
    License
    MIT
    Last updated
    10 months ago
    Downloads
    42K

    #mizchi/js

    Comprehensive JavaScript/ FFI bindings for MoonBit, supporting multiple runtimes and platforms.

    #Installation

    $ moon add mizchi/js

    Add to your moon.pkg.json:

    { "import": ["mizchi/js"] }

    ⚠️ Future Plans: Platform-specific APIs (Node.js, Browser, Deno, Cloudflare Workers) will be split into separate packages in the future. The core mizchi/js package will focus on JavaScript built-ins and Web Standard APIs.

    #📚 API Documentation by Platform

    PlatformDocumentationExamplesStatus
    Core JavaScriptsrc/README.mdjs_examples.mbt.md🧪 Tested
    Browsersrc/browser/README.mdbrowser_examples.mbt.md🧪 Tested
    Node.jssrc/node/README.mdnode_examples.mbt.md🧪 Tested
    Denosrc/deno/README.md-🧪 Tested
    Cloudflare Workerssrc/cloudflare/README.mdcfw/🧪 Tested
    Reactsrc/npm/react/react_app/🧪 Tested

    #📖 Learning Resources

    #Supported Modules

    #Status Legend

    • 🧪 Tested: Comprehensive test coverage, production ready
    • 🚧 Partially: Core functionality implemented, tests incomplete
    • 🤖 AI Generated: FFI bindings created, needs testing
    • 📅 Planned: Scheduled for future implementation
    • ❌ Not Supported: Technical limitations

    #Core JavaScript APIs

    CategoryPackageStatusNote
    Core FFI & Objects
    Core FFImizchi/js🧪 Testedget, set, call, etc.
    Objectmizchi/js🧪 TestedObject manipulation
    Functionmizchi/js🧪 TestedFunction operations
    Promisemizchi/js🧪 TestedAsync/Promise API
    Errormizchi/js🧪 TestedError handling
    JSONmizchi/js🧪 TestedJSON parse/stringify
    Iteratormizchi/js🧪 TestedJS Iterator protocol
    AsyncIteratormizchi/js🧪 TestedAsync iteration
    WeakMap/Set/Refmizchi/js🧪 TestedWeak references
    Async Helpers
    run_asyncmizchi/js🧪 TestedAsync execution
    suspendmizchi/js🧪 TestedPromise suspension
    sleepmizchi/js🧪 TestedDelay execution
    promisifymizchi/js🧪 TestedCallback → Promise

    #JavaScript Built-ins

    CategoryPackageStatusNote
    ArrayBuffermizchi/js/builtins/arraybuffer🧪 TestedBinary buffers
    TypedArraysmizchi/js/builtins/typedarray🧪 TestedUint8Array, etc.
    DataViewmizchi/js/builtins/arraybuffer🧪 TestedBuffer views
    SharedArrayBuffermizchi/js/builtins/arraybuffer🤖 AI GeneratedShared memory
    RegExpmizchi/js/builtins/regexp🧪 TestedRegular expressions
    Datemizchi/js/builtins/date🧪 TestedDate/time operations
    Mathmizchi/js/builtins/math🧪 TestedMath operations
    Reflectmizchi/js/builtins/reflect🤖 AI GeneratedReflection API
    Proxymizchi/js/builtins/proxy🤖 AI GeneratedProxy API

    #Web Standard APIs

    Platform-independent Web Standard APIs (browsers, Node.js, Deno, edge runtimes):

    See mizchi/js/web for detailed Web APIs documentation

    CategoryPackageStatusNote
    Consolemizchi/js/web/console🧪 Testedconsole.log, console.error, etc.
    fetchmizchi/js/web/http🧪 TestedHTTP requests
    Requestmizchi/js/web/http🧪 TestedRequest objects
    Responsemizchi/js/web/http🧪 TestedResponse objects
    Headersmizchi/js/web/http🧪 TestedHTTP headers
    FormDatamizchi/js/web/http🧪 TestedForm data
    URLmizchi/js/web/url🧪 TestedURL parsing
    URLSearchParamsmizchi/js/web/url🧪 TestedQuery strings
    URLPatternmizchi/js/web/url🧪 TestedURL pattern matching
    Blobmizchi/js/web/blob🧪 TestedBinary data
    ReadableStreammizchi/js/web/streams🧪 TestedStream reading
    WritableStreammizchi/js/web/streams🧪 TestedStream writing
    TransformStreammizchi/js/web/streams🧪 TestedStream transformation
    CompressionStreammizchi/js/web/streams🧪 TestedGZIP/Deflate compression
    DecompressionStreammizchi/js/web/streams🧪 TestedGZIP/Deflate decompression
    TextEncodermizchi/js/web/encoding🧪 TestedString to Uint8Array
    TextDecodermizchi/js/web/encoding🧪 TestedUint8Array to String
    Eventmizchi/js/web/event🧪 TestedEvent objects
    CustomEventmizchi/js/web/event🧪 TestedCustom events
    MessageEventmizchi/js/web/event🧪 TestedMessage events
    Cryptomizchi/js/web/crypto🧪 TestedWeb Crypto API
    WebSocketmizchi/js/web/websocket🧪 TestedWebSocket API
    Workermizchi/js/web/worker🧪 TestedWeb Workers
    MessageChannelmizchi/js/web/message🧪 TestedMessage passing
    MessagePortmizchi/js/web/message🧪 TestedMessage ports
    WebAssemblymizchi/js/web/webassembly🤖 AI GeneratedWASM integration
    Performancemizchi/js/web/performance🤖 AI GeneratedPerformance API

    #Runtime-Specific APIs

    PlatformPackageStatusDocumentation
    Node.jsmizchi/js/node/*🧪 TestedNode.js README
    Browser APImizchi/js/browser/*🧪 TestedBrowser README
    Denomizchi/js/deno🧪 TestedDeno README
    Cloudflare Workersmizchi/js/cloudflare🧪 TestedCloudflare README

    #NPM Package Bindings

    See src/npm/README.md for full npm package documentation

    CategoryPackagesStatus
    UI FrameworksReact, React DOM, React Router, Preact, Ink🧪 Tested
    Web FrameworksHono, better-auth🧪 Tested
    AI / LLMVercel AI SDK, MCP SDK, Claude Code SDK🧪 Tested
    Cloud Services@aws-sdk/client-s3 (S3, R2, GCS, MinIO)🧪 Tested
    DatabasePGlite, DuckDB, Drizzle, pg🧪 Tested
    ValidationZod, AJV🧪 Tested
    Build ToolsTerser, Vite, Unplugin, Lighthouse🧪 Tested
    Utilitiesdate-fns, semver, chalk, dotenv, chokidar, yargs, debug🧪 Tested
    TestingTesting Library, Puppeteer, Playwright, Vitest, JSDOM, MSW🧪 Tested
    Parsinghtmlparser2, js-yaml🧪 Tested
    Othersimple-git, ignore, memfs, source-map, comlink🧪 Tested

    #Not Supported APIs

    FeatureReason
    eval()Security and type safety
    new Function()Security and type safety
    DisposableStackNo using keyword in MoonBit
    AsyncDisposableStackNo await using keyword in MoonBit

    #Project Status

    • ✅ React SPA - Full support with SSR/CSR
    • ✅ Node.js Core APIs - fs, path, process, child_process, etc.
    • ✅ Cloudflare Workers - KV, D1, R2, Durable Objects
    • ✅ Deno Runtime - File system, permissions, testing
    • ✅ DOM APIs - Full browser DOM manipulation
    • 🤖 AI-Generated Bindings - Many APIs generated from TypeScript definitions

    #Goals

    • Provide comprehensive JavaScript bindings for MoonBit
    • Platform Coverage
      • ✅ Browser + React for frontend development
      • ✅ Node.js/Deno support to replace TypeScript
      • ✅ Cloudflare Workers for edge computing
      • ✅ MCP server/client support

    #Quick Start

    #Basic FFI Operations

    // Create JavaScript objects
    let obj = @js.from_map({ "name": @core.any("Alice"), "age": @core.any(30) })

    // Get property
    let name = obj._get("name")

    // Set property
    obj.set("age", 31)

    // Call method
    let result = obj._call("toString", [])

    // Type casting
    let age: Int = obj._get("age").cast()

    #LICENSE

    MIT

    #mizchi/js - Core Package

    Core JavaScript FFI bindings package. This is the foundation package that provides:

    • Core FFI operations (get, set, call, cast, etc.)
    • JavaScript built-in types (Object, Array, Promise, Function, Error, etc.)
    • Async helpers (run_async, suspend, sleep, promisify)
    • Type conversion utilities

    #Installation

    moon add mizchi/js

    Add to your moon.pkg.json:

    { "import": ["mizchi/js"] }

    #Basic Usage

    #Core FFI Operations

    // Create objects
    let obj = @core.Object::new()
    obj.set("name", "Alice")
    obj.set("age", 30)

    // Get properties
    let name = obj._get("name") // Returns @core.Any
    let age: Int = obj._get("age").cast() // Type-safe casting

    // Call methods
    let has_name: Bool = obj._call("hasOwnProperty", ["name"]).cast()

    // Create from map
    let obj2 = @js.from_map({ "x": @core.any(10), "y": @core.any(20) })

    #Type Casting

    // Using cast() method (recommended)
    let value: Int = js_value.cast()
    let str: String = js_value.cast()

    // Using identity() for low-level FFI
    let value: Int = @js.identity(js_value)

    // Optional types
    let nullable: Int? = @js.identity_option(js_value)

    #Promises and Async

    // Create and use promises
    let promise = @js.Promise::resolve(42)
    promise.then_(fn(value) {
    @console.log(value)
    })

    // Async/await
    async fn example() -> Int {
    let promise = @js.Promise::resolve(42)
    let value = promise.wait()
    value
    }

    // Run async code
    @js.run_async(async fn() {
    let value = some_promise.wait()
    @console.log(value)
    })

    #Async Helpers

    // Sleep
    async fn delayed() -> Unit {
    @js.sleep(1000) // Sleep for 1 second
    @console.log("Delayed!")
    }

    // Promisify callbacks
    let async_fn = async fn(x: Int) -> String {
    @js.sleep(100)
    x.to_string()
    }
    let promise_fn = @js.promisify1(async_fn)
    let promise = promise_fn(42) // Returns Promise[String]

    #Arrays

    // Create arrays
    let arr = @js.JsArray::new()
    arr.push(1)
    arr.push(2)
    arr.push(3)

    // Array operations
    let length = arr.length()
    let first = arr._get(0)
    arr.set(1, 42)

    // From MoonBit Array
    let mbt_arr = [1, 2, 3]
    let js_arr = @js.JsArray::from_array(mbt_arr)

    #Error Handling

    // Create errors
    let err = @js.Error::new("Something went wrong")

    // Throw errors (use in FFI functions marked with `raise`)
    fn example() -> Int raise {
    fail("Error message")
    }

    // Catch errors in async
    async fn safe_operation() -> Unit {
    try {
    let result = risky_operation().wait()
    @console.log(result)
    } catch {
    e => @console.error("Error: " + e.to_string())
    }
    }

    #JSON Operations

    // Parse JSON
    let json_str = "{\"name\":\"Alice\",\"age\":30}"
    let obj = @js.JSON::parse(json_str)

    // Stringify
    let obj = @js.from_map({ "name": @core.any("Alice"), "age": @core.any(30) })
    let json_str = @js.JSON::stringify(obj)

    // With formatting
    let pretty = @js.JSON::stringify_with_indent(obj, 2)

    #Nullish Handling

    // Nullish[T] handles both null and undefined
    let nullish: @js.Nullish[Int] = @js.null()

    match nullish.to_option() {
    Some(value) => @console.log(value)
    None => @console.log("null or undefined")
    }

    // Nullable[T] only handles null
    let nullable: @js.Nullable[Int] = @js.Nullable::null()

    #Iterators

    // JavaScript iterator
    let iter = js_array.values()
    loop {
    let next = iter.next()
    if next.done {
    break
    }
    @console.log(next.value)
    }

    // Async iterator
    async fn iterate_async(iter: @js.AsyncIterator) -> Unit {
    loop {
    let next = iter.next().wait()
    if next.done {
    break
    }
    @console.log(next.value)
    }
    }

    #Understanding Core FFI Types

    When reading test code or using this library, you'll encounter several core types and functions for bridging MoonBit and JavaScript. This section explains what they are and when to use them.

    #@core.Any - The Universal JavaScript Type

    @core.Any represents any JavaScript value (similar to TypeScript's any). It's the foundation type for all JavaScript interop.

    // @core.Any can hold any JavaScript value
    let num : @core.Any = @core.any(42) // number
    let str : @core.Any = @core.any("hello") // string
    let obj : @core.Any = @core.Object::new() // object

    When you see @core.Any in code: This value came from JavaScript and its type is unknown at compile time.

    #@core.any() - Converting MoonBit Values to JavaScript

    @core.any() converts MoonBit values that implement JsImpl trait to @core.Any.

    // Convert MoonBit values to JavaScript
    let js_int = @core.any(42) // Int → @core.Any
    let js_str = @core.any("hello") // String → @core.Any
    let js_bool = @core.any(true) // Bool → @core.Any
    let js_arr = @core.any([1, 2, 3]) // Array → @core.Any

    When to use: When passing MoonBit values to JavaScript APIs that expect dynamic types.

    #@js.identity() - Unsafe Type Casting

    @js.identity() performs an unsafe cast between any two types. It's used to convert @core.Any back to typed MoonBit values.

    // Cast @core.Any to specific types (unsafe!)
    let js_value : @core.Any = obj._get("count")
    let count : Int = @js.identity(js_value)

    // Common pattern: inline casting
    let name : String = @js.identity(obj._get("name"))

    Warning: @js.identity() does no runtime checking. If the JavaScript value isn't the expected type, you'll get undefined behavior.

    Alternative: Use .cast() method which is equivalent but more readable:
    let count : Int = obj._get("count").cast()

    #JsImpl Trait - Types That Can Interop with JavaScript

    JsImpl is a trait for types that can be safely converted to JavaScript values. All JavaScript wrapper types and MoonBit primitives implement this trait.

    // These types implement JsImpl:
    // - @core.Any, @js.Object, @js.JsArray, @js.Promise[T], etc.
    // - MoonBit primitives: String, Int, Double, Bool, etc.
    // - Array[T] where T : JsImpl

    // JsImpl provides these methods:
    trait JsImpl {
    as_any(Self) -> Any // Convert to @core.Any
    get(Self, key) -> Any // JS: self[key]
    set(Self, key, val) -> Unit // JS: self[key] = val
    call(Self, key, args) -> Any // JS: self[key](...args)
    // ... and more
    }

    When you see &JsImpl in function signatures: The function accepts any type that can be converted to JavaScript.

    #Common Patterns in Test Code

    #Pattern 1: Getting typed values from JavaScript objects

    // JavaScript: const name = obj.name
    let name : String = @js.identity(obj._get("name"))

    // Alternative using cast()
    let age : Int = obj._get("age").cast()

    #Pattern 2: Creating JavaScript objects with MoonBit values

    // Using from_map (recommended)
    let obj = @js.from_map({
    "name": @core.any("Alice"),
    "age": @core.any(30)
    })

    // Manual construction
    let obj = @core.Object::new()
    obj.set("name", "Alice") // String implements JsImpl
    obj.set("age", 30) // Int implements JsImpl

    #Pattern 3: Handling nullable/optional values

    // JavaScript null/undefined → MoonBit Option
    let maybe_value : Int? = @js.identity_option(obj._get("optional_field"))

    // MoonBit Option → JavaScript null
    let js_value = @js.from_option(Some(42)) // → 42
    let js_null = @js.from_option(None) // → null

    #Pattern 4: Calling JavaScript methods

    // No arguments: obj.method()
    let result = obj.call0("method")

    // With arguments: obj.method(arg1, arg2)
    let result = obj._call("method", [arg1, arg2])

    // With type casting
    let str_result : String = obj.call0("toString").cast()

    #Summary Table

    Function/TypePurposeExample
    @core.AnyUniversal JS value typelet v : @core.Any = ...
    @core.any(x)MoonBit → JS conversion@core.any(42)
    @js.identity(x)Unsafe type castlet n : Int = @js.identity(v)
    .cast()Same as identity (method)v.cast()
    JsImplTrait for JS-compatible typesfn foo(x : &JsImpl)
    .as_any()Convert to @core.Anyobj.as_any()
    ._get(key)Property accessobj._get("name")
    .set(key, val)Property assignmentobj.set("age", 30)

    #Advanced Patterns

    #Escape Hatch Pattern

    When you need to access JavaScript APIs not yet wrapped in this library:

    // Define external FFI function
    extern "js" fn ffi_my_custom_api(arg: @core.Any) -> @core.Any =
    #|arg => {
    #| // JavaScript code here
    #| return arg.customMethod();
    #|}

    // Wrap it in a type-safe function
    pub fn my_custom_api(value: String) -> String {
    let result = ffi_my_custom_api(value)
    result.cast()
    }

    See escape_hatch.mbt.md for more patterns.

    #Type Reference

    #Core Types

    • @core.Any - Universal JavaScript value type (was @js.Js before v0.5.0)
    • @js.Object - JavaScript object
    • @js.JsArray - JavaScript array
    • @js.Promise[T] - JavaScript Promise
    • @js.Function - JavaScript function
    • @js.Error - JavaScript Error

    #Nullish Types

    • @js.Nullish[T] - Handles both null and undefined (converts to Option[T])
    • @js.Nullable[T] - Handles only null
    • @js.Undefinedable[T] - Handles only undefined

    #Binary Data

    See mizchi/js/builtins/arraybuffer and mizchi/js/builtins/typedarray packages.

    This core package is used by:

    • mizchi/js/web/* - Web Standard APIs
    • mizchi/js/browser/* - Browser DOM APIs
    • mizchi/js/node/* - Node.js runtime APIs
    • mizchi/js/cloudflare/* - Cloudflare Workers APIs
    • mizchi/js/npm/* - NPM package bindings

    See the main project README for the complete package list.

    #Migration from v0.4.0

    #Breaking Changes in v0.5.0

    // Type rename: @js.Js → @core.Any
    let value: @core.Any = obj._get("key")

    // Method rename: to_js() → as_any()
    let any = obj.as_any()

    // Function rename: @js.js() → @core.any()
    let converted = @core.any(value)

    // Casting: unsafe_cast() → identity() or cast()
    let typed: Int = value.cast()

    #Contributing

    See the main project documentation for contribution guidelines.

    AbortController

    JavaScript: AbortController and AbortSignal for future integration with async operations

    AbortSignal

    JavaScript: AbortController and AbortSignal for future integration with async operations

    Any

    Opaque type for JavaScript values

    ArrayBuffer

    https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer

    AsyncIterator

    JavaScript AsyncIterator https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/AsyncIterator

    JsIterator

    JavaScript Iterator https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Iterator

    Nullable

    null or T

    Nullish

    null | undefined | T

    Object

    JavaScript Object

    Promise

    JavaScript Promise[T] https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise

    Symbol

    JavaScript Symbol

    TypedArray

    TypedArray の共通操作をまとめたベース型。 具体的な TypedArray 型から as_typed_array() でダウンキャストして利用する。

    ThrowError

    pub suberror ThrowError
    Any

    impl Show for ThrowError

    JSON

    #external
    pub type JSON

    JavaScript: JSON

    JSON::parse

    fn JSON::parse(s : String, reviver? :
    Any
    ?) ->
    Any
    raise ThrowError

    JS: JSON.parse(s, reviver)

    JSON::stringify

    fn JSON::stringify(v :
    Any
    , replacer? :
    Any
    , space? : Int) -> String

    JS: JSON.stringify(v, replacer, space)

    JsArray

    #external
    pub type JsArray

    JavaScript Array NonGeneric Array only for Array[Any] Use builtin Array[T] for generic array and JsArray::from(array)

    JsArray::as_any

    fn JsArray::as_any(self : JsArray) ->
    Any

    JsArray::as_builtin_array

    fn[T] JsArray::as_builtin_array(self : JsArray) -> Array[T]

    cast to builtin Array

    JsArray::to_string

    fn JsArray::to_string(self : JsArray) -> String

    JsError

    pub(all) struct JsError {
    message : String
    stack : String
    }

    JsError::isError

    fn JsError::isError(value :
    Any
    ) -> Bool

    JsError::new

    fn JsError::new(message : String, cause? : JsError) -> JsError

    JsString

    #external
    pub type JsString

    JsString::fromCharCode

    fn JsString::fromCharCode(values : Array[Int]) -> String

    JS: String.fromCharCode(...values)

    JsString::fromCodePoint

    fn JsString::fromCodePoint(values : Array[Int]) -> String

    JS: String.fromCodePoint(...values)

    JsString::to_any

    PromiseResolvers

    pub(all) struct PromiseResolvers[T] {
    promise :
    Promise
    [T]
    resolve : (T) -> Unit
    reject : (Error) -> Unit
    }

    JS: Promise.withResolvers() https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/withPromiseResolvers

    PromiseResolvers::reject

    fn[T] PromiseResolvers::reject(self : PromiseResolvers[T], error : Error) -> Unit

    JS: resolvers.reject(error)

    PromiseResolvers::resolve

    fn[T] PromiseResolvers::resolve(self : PromiseResolvers[T], value : T) -> Unit

    JS: resolvers.resolve(value)

    any

    fn[T] any(value : T) ->
    Any

    from_fn0

    fn[A] from_fn0(f : () -> A) ->
    Any

    Wrap MoonBit function as JS function (0 args)

    from_fn1

    fn[A, B] from_fn1(f : (A) -> B) ->
    Any

    Wrap MoonBit function as JS function (1 arg)

    from_fn2

    fn[A, B, C] from_fn2(f : (A, B) -> C) ->
    Any

    Wrap MoonBit function as JS function (2 args)

    from_fn3

    fn[A, B, C, D] from_fn3(f : (A, B, C) -> D) ->
    Any

    Wrap MoonBit function as JS function (3 args)

    identity

    fn[A, B] identity(value : A) -> B

    log

    fn[T] log(v : T) -> Unit

    JS: console.log(v)

    log2

    fn[T, U] log2(a : T, b : U) -> Unit

    JS: console.log(a, b)

    new

    JS: new cls(...args)

    promisify0

    fn[R] promisify0(f : async () -> R) -> (() ->
    Promise
    [R])

    promisify1

    fn[A, R] promisify1(f : async (A) -> R) -> ((A) ->
    Promise
    [R])

    Moonbit Async Function to JS Promise Function

    promisify2

    fn[A, B, R] promisify2(f : async (A, B) -> R) -> ((A, B) ->
    Promise
    [R])

    Moonbit Async Function to JS Promise Function

    promisify3

    fn[A, B, C, R] promisify3(f : async (A, B, C) -> R) -> ((A, B, C) ->
    Promise
    [R])

    Moonbit Async Function to JS Promise Function

    run_async

    fn run_async(f : async () -> Unit noraise) -> Unit

    MoonBit builtin %async.run

    suspend

    async fn[T, E : Error] suspend(f : ((T) -> Unit, (E) -> Unit) -> Unit) -> T raise E

    MoonBit builtin %async.suspend

    symbol

    fn symbol(name : String) ->
    Symbol

    JS: Symbol(name)

    throwable

    fn[T] throwable(f : () -> T raise?) -> T raise ThrowError

    Wraps a synchronous function call, converting any thrown JS errors into ThrowError
    let result = throwable(() => undefined()._invoke([]))

    typeof_

    fn typeof_(v :
    Any
    ) -> String

    JS: typeof v