Sign in

    opendal

    MoonBit bindings for Apache OpenDAL

    Download zip
    Version
    0.2.0
    License
    Apache-2.0
    Last updated
    2 months ago
    Downloads
    29

    #Apache OpenDAL for MoonBit

    OpenDAL provides one storage API over different storage services. This binding presents one ordinary MoonBit package on native and JavaScript targets: behavior lives on resource types such as Operator, AsyncReadStream, and AsyncWriter; asynchronous I/O uses MoonBit async fn; the native ABI and the embedded browser runtime stay private.

    #Release and source status

    Version 0.2.0 is the current release line. Version 0.1.0 remains an immutable compatibility baseline for applications that only need the original native memory/fs surface:

    TrackServices and APINative hosts
    Current Eric-Song-Nop/opendal@0.2.0standard profile: memory, fs, typed s3, complete Phase 5A-E API, and Browser JSApple silicon macOS 11+, x86-64 and arm64 glibc Linux 2.35+
    Legacy Eric-Song-Nop/opendal@0.1.0local profile: memory, fs, synchronous Phase 1-4 APIApple silicon macOS 11+, x86-64 glibc Linux 2.35+

    This source tree selects the fully pinned native/artifacts-standard.json table for 0.2.0-r2. The immutable v0.1.0-r1 local records remain unchanged in native/artifacts.json.

    The current source facade implements:

    • whole, ranged, random-access, and output-bounded sequential reads;
    • whole and chunked writes with explicit finish or abort;
    • metadata, existence, directories, listing, delete, copy, and rename;
    • typed S3 construction with default-chain, static/session, unsigned, and assume-role authentication;
    • owned presigned read/write/stat requests;
    • immutable timeout, retry, and concurrency-limit layers, all opt-in;
    • all-or-error delete_many and a managed same-Operator, one-object Copier;
    • one root-package async facade for whole writes and reads, bounded read streams, and explicit streaming writers on native and browser JS targets;
    • an embedded browser OpenDAL Wasm runtime with additional async operations and listers;
    • typed OpenDalError values and capability inspection.

    The checked-in native public interface is src/pkg.generated.mbti. Use moon ide doc --target js'@opendal' for the target-specific browser surface.

    #Install a release

    Add the standard release like any other Moon package:

    moon add Eric-Song-Nop/opendal@0.2.0

    Use the legacy release only when an application intentionally targets its smaller native-only compatibility surface:

    moon add Eric-Song-Nop/opendal@0.1.0

    Import the same root package from native and JavaScript packages:

    supported_targets = "+native+js"

    import {
    "Eric-Song-Nop/opendal",
    }

    No OpenDAL-specific linker flags are required. Native remains the default target; pass --target js for a browser build. On the first native build, the package downloads and verifies the release artifact for the current host; later builds reuse Moon's shared cache. JavaScript builds use the embedded browser runtime and do not download a native archive. The current prebuild hook requires Node.js 18 or newer; native builds also require tar. Consumers do not need Rust, Cargo, or this repository.

    Only Moon's native and js targets are supported. wasm and wasm-gc are not browser aliases for this binding; browser applications compile to the JS target, which hosts the embedded OpenDAL core Wasm runtime. Portable native async operations run as Rust Tokio tasks and wake Moon through a nonblocking completion pipe; browser operations use Promises and AbortSignal.

    Contributors validating changes from a source checkout use:

    make moon-deps make test-profile NATIVE_SERVICE_PROFILE=standard

    That maintainer path builds and overlays a standard archive from source for validation; it neither rewrites the committed v0.2.0 standard pins nor changes the immutable v0.1.0 local table.

    #Browser quickstart

    From either this repository root or the root of the unpacked Moon package, one Moon command compiles the published demo and runs its OpenDAL round trip in a real headless Chrome or Chromium:

    moon run --target js --release src/browser_demo

    The command needs MoonBit, Node.js 18 or newer, and an installed Chrome or Chromium (CHROME_BIN can select it). It needs no Rust toolchain, npm package, JavaScript bundler, CDN, or separately served Wasm asset.

    Browser consumers use the same root import as native consumers:

    supported_targets = "js"

    import {
    "Eric-Song-Nop/opendal",
    "moonbitlang/async",
    }

    Inside an async context, AsyncOperator::new initializes the target-specific backend. On JavaScript it lazily boots the version-matched runtime embedded in the Moon package:

    ///|
    async fn browser_round_trip() {
    let storage = @opendal.AsyncOperator::new("memory")
    defer storage.close()
    storage.write("hello.txt", b"hello from Chrome") |> ignore
    assert_eq(storage.read("hello.txt"), b"hello from Chrome")
    }

    The compatibility Eric-Song-Nop/opendal/browser import and explicit Runtime::load(BrowserAssets) remain available for applications that manage version-matched runtime, glue, and Wasm URLs themselves. Maintainers refresh the checked-in embedded source with make browser-embed-generate and validate it with make browser-embed-check; the check verifies the compressed payload, its source fingerprint, exported Wasm interface, generated glue, and Promise runtime. CI then executes both the freshly rebuilt bridge and the packaged embedded bridge in real Chrome. A browser host page's Content Security Policy must allow WebAssembly compilation, normally by including script-src 'wasm-unsafe-eval'; the published demo sets this policy itself. See Using OpenDAL in a browser for OPFS and browser S3 configuration, CORS and hosting requirements, JS-only operations, runtime ownership, cancellation, and hard bridge limits. The examples/browser program runs shared portable async code on native and in real Chrome. Its Browser command and native verification target also run the same delayed S3 heartbeat proof that pending OpenDAL I/O does not block MoonBit's scheduler.

    #First operation

    memory is the quickest way to try the API because it needs no configuration:

    ///|
    #cfg(target="native")
    test "README: memory round trip" {
    let operator = @opendal.Operator::new("memory")
    operator.write("hello.txt", b"hello from MoonBit") |> ignore
    assert_eq(operator.read("hello.txt"), b"hello from MoonBit")
    }

    Methods that can fail use MoonBit's checked-error effect:

    ///|
    #cfg(target="native")
    test "README: typed storage error" {
    let operator = @opendal.Operator::new("memory")
    try operator.read("missing.txt") catch {
    error => {
    assert_true(error.kind() is NotFound)
    assert_true(error.info().operation is Read)
    assert_eq(error.info().path, Some("missing.txt"))
    }
    } noraise {
    _ => fail("expected a missing-object error")
    }
    }

    Async methods are called directly inside an async context; MoonBit has no await keyword:

    ///|
    async test "README: async memory round trip" {
    let async_operator = @opendal.AsyncOperator::new("memory")
    defer async_operator.close()
    async_operator.write("whole.txt", b"whole object") |> ignore
    assert_eq(async_operator.read("whole.txt"), b"whole object")
    let writer = async_operator.open_writer("async.txt")
    writer.write(b"hello ")
    writer.write(b"asynchronously")
    writer.finish() |> ignore
    assert_eq(async_operator.read("async.txt"), b"hello asynchronously")
    }

    MoonBit async catch clauses receive the target-neutral Error type. Use OpenDalError::from_error(error) to recover the structured category, status, operation, and path on either target.

    #Guides

    • Documentation index — user guides, target-specific API reference, architecture contracts, release procedure, and examples.
    • Getting started — install v0.2.0 or validate a source checkout, then choose synchronous or async I/O.
    • Connecting — understand profiles and construct memory, filesystem, and typed S3 operators.
    • Using OpenDAL in a browser — select the JS target, use the embedded runtime, configure OPFS or S3, and deploy it safely.
    • Common tasks — recipes for streams, abort, presign, layers, batch deletion, Copier, async I/O, and the blocking core.
    • Roadmap — completed Phase 5 slices and the remaining release gates.

    #Deliberate limits

    • Native source builds enable memory, fs, and s3; browser JS builds enable memory, opfs, and s3. GCS, Azure Blob, WebDAV, and other OpenDAL services are not compiled in.
    • delete_many is all-or-error and can have partial remote effects; it does not fabricate ordered per-path results or promise atomicity.
    • Copier copies one object between two paths on the same Operator. It is not recursive and cannot bridge two operators or services.
    • ReadStream.chunk_size hard-bounds each returned value and binding copy, but OpenDAL or a backend may provide and retain one larger raw buffer internally.
    • Suffix ranges require capability.can_read_suffix(); the binding does not emulate suffix reads with a preliminary stat.
    • The portable async slice covers whole writes and reads, bounded read streams, and chunked writers. Whole-object buffers are limited to 64 MiB and stream and writer chunks to 256 KiB on both targets. Native async stat/list/delete/copy/presign and public task handles remain later work; the JavaScript target additionally exposes its capability-checked Promise operations and stateful listers.
    • Retry, timeout, and concurrency limits are never implicit. Logging, tracing, metrics exporters, and custom callback layers are not exposed.
    • Standard artifacts are published for v0.2.0. Intel macOS, Windows, and musl Linux are not advertised; a Rust-only build is not treated as MoonBit host support.

    Passing an arbitrary scheme does not install a backend. ABI feature presence, selected-profile services, and a backend's operation capabilities are separate checks; unsupported services and operations raise OpenDalError instead of silently falling back.

    #Upstream references

    The organization of these guides follows Apache OpenDAL's official Node.js binding documentation while keeping the smaller MoonBit contracts explicit:

    #Apache OpenDAL for MoonBit

    OpenDAL provides one storage API over different storage services. This binding presents one ordinary MoonBit package on native and JavaScript targets: behavior lives on resource types such as Operator, AsyncReadStream, and AsyncWriter; asynchronous I/O uses MoonBit async fn; the native ABI and the embedded browser runtime stay private.

    #Release and source status

    Version 0.2.0 is the current release line. Version 0.1.0 remains an immutable compatibility baseline for applications that only need the original native memory/fs surface:

    TrackServices and APINative hosts
    Current Eric-Song-Nop/opendal@0.2.0standard profile: memory, fs, typed s3, complete Phase 5A-E API, and Browser JSApple silicon macOS 11+, x86-64 and arm64 glibc Linux 2.35+
    Legacy Eric-Song-Nop/opendal@0.1.0local profile: memory, fs, synchronous Phase 1-4 APIApple silicon macOS 11+, x86-64 glibc Linux 2.35+

    This source tree selects the fully pinned native/artifacts-standard.json table for 0.2.0-r2. The immutable v0.1.0-r1 local records remain unchanged in native/artifacts.json.

    The current source facade implements:

    • whole, ranged, random-access, and output-bounded sequential reads;
    • whole and chunked writes with explicit finish or abort;
    • metadata, existence, directories, listing, delete, copy, and rename;
    • typed S3 construction with default-chain, static/session, unsigned, and assume-role authentication;
    • owned presigned read/write/stat requests;
    • immutable timeout, retry, and concurrency-limit layers, all opt-in;
    • all-or-error delete_many and a managed same-Operator, one-object Copier;
    • one root-package async facade for whole writes and reads, bounded read streams, and explicit streaming writers on native and browser JS targets;
    • an embedded browser OpenDAL Wasm runtime with additional async operations and listers;
    • typed OpenDalError values and capability inspection.

    The checked-in native public interface is src/pkg.generated.mbti. Use moon ide doc --target js'@opendal' for the target-specific browser surface.

    #Install a release

    Add the standard release like any other Moon package:

    moon add Eric-Song-Nop/opendal@0.2.0

    Use the legacy release only when an application intentionally targets its smaller native-only compatibility surface:

    moon add Eric-Song-Nop/opendal@0.1.0

    Import the same root package from native and JavaScript packages:

    supported_targets = "+native+js"

    import {
    "Eric-Song-Nop/opendal",
    }

    No OpenDAL-specific linker flags are required. Native remains the default target; pass --target js for a browser build. On the first native build, the package downloads and verifies the release artifact for the current host; later builds reuse Moon's shared cache. JavaScript builds use the embedded browser runtime and do not download a native archive. The current prebuild hook requires Node.js 18 or newer; native builds also require tar. Consumers do not need Rust, Cargo, or this repository.

    Only Moon's native and js targets are supported. wasm and wasm-gc are not browser aliases for this binding; browser applications compile to the JS target, which hosts the embedded OpenDAL core Wasm runtime. Portable native async operations run as Rust Tokio tasks and wake Moon through a nonblocking completion pipe; browser operations use Promises and AbortSignal.

    Contributors validating changes from a source checkout use:

    make moon-deps make test-profile NATIVE_SERVICE_PROFILE=standard

    That maintainer path builds and overlays a standard archive from source for validation; it neither rewrites the committed v0.2.0 standard pins nor changes the immutable v0.1.0 local table.

    #Browser quickstart

    From either this repository root or the root of the unpacked Moon package, one Moon command compiles the published demo and runs its OpenDAL round trip in a real headless Chrome or Chromium:

    moon run --target js --release src/browser_demo

    The command needs MoonBit, Node.js 18 or newer, and an installed Chrome or Chromium (CHROME_BIN can select it). It needs no Rust toolchain, npm package, JavaScript bundler, CDN, or separately served Wasm asset.

    Browser consumers use the same root import as native consumers:

    supported_targets = "js"

    import {
    "Eric-Song-Nop/opendal",
    "moonbitlang/async",
    }

    Inside an async context, AsyncOperator::new initializes the target-specific backend. On JavaScript it lazily boots the version-matched runtime embedded in the Moon package:

    ///|
    async fn browser_round_trip() {
    let storage = @opendal.AsyncOperator::new("memory")
    defer storage.close()
    storage.write("hello.txt", b"hello from Chrome") |> ignore
    assert_eq(storage.read("hello.txt"), b"hello from Chrome")
    }

    The compatibility Eric-Song-Nop/opendal/browser import and explicit Runtime::load(BrowserAssets) remain available for applications that manage version-matched runtime, glue, and Wasm URLs themselves. Maintainers refresh the checked-in embedded source with make browser-embed-generate and validate it with make browser-embed-check; the check verifies the compressed payload, its source fingerprint, exported Wasm interface, generated glue, and Promise runtime. CI then executes both the freshly rebuilt bridge and the packaged embedded bridge in real Chrome. A browser host page's Content Security Policy must allow WebAssembly compilation, normally by including script-src 'wasm-unsafe-eval'; the published demo sets this policy itself. See Using OpenDAL in a browser for OPFS and browser S3 configuration, CORS and hosting requirements, JS-only operations, runtime ownership, cancellation, and hard bridge limits. The examples/browser program runs shared portable async code on native and in real Chrome. Its Browser command and native verification target also run the same delayed S3 heartbeat proof that pending OpenDAL I/O does not block MoonBit's scheduler.

    #First operation

    memory is the quickest way to try the API because it needs no configuration:

    ///|
    #cfg(target="native")
    test "README: memory round trip" {
    let operator = @opendal.Operator::new("memory")
    operator.write("hello.txt", b"hello from MoonBit") |> ignore
    assert_eq(operator.read("hello.txt"), b"hello from MoonBit")
    }

    Methods that can fail use MoonBit's checked-error effect:

    ///|
    #cfg(target="native")
    test "README: typed storage error" {
    let operator = @opendal.Operator::new("memory")
    try operator.read("missing.txt") catch {
    error => {
    assert_true(error.kind() is NotFound)
    assert_true(error.info().operation is Read)
    assert_eq(error.info().path, Some("missing.txt"))
    }
    } noraise {
    _ => fail("expected a missing-object error")
    }
    }

    Async methods are called directly inside an async context; MoonBit has no await keyword:

    ///|
    async test "README: async memory round trip" {
    let async_operator = @opendal.AsyncOperator::new("memory")
    defer async_operator.close()
    async_operator.write("whole.txt", b"whole object") |> ignore
    assert_eq(async_operator.read("whole.txt"), b"whole object")
    let writer = async_operator.open_writer("async.txt")
    writer.write(b"hello ")
    writer.write(b"asynchronously")
    writer.finish() |> ignore
    assert_eq(async_operator.read("async.txt"), b"hello asynchronously")
    }

    MoonBit async catch clauses receive the target-neutral Error type. Use OpenDalError::from_error(error) to recover the structured category, status, operation, and path on either target.

    #Guides

    • Documentation index — user guides, target-specific API reference, architecture contracts, release procedure, and examples.
    • Getting started — install v0.2.0 or validate a source checkout, then choose synchronous or async I/O.
    • Connecting — understand profiles and construct memory, filesystem, and typed S3 operators.
    • Using OpenDAL in a browser — select the JS target, use the embedded runtime, configure OPFS or S3, and deploy it safely.
    • Common tasks — recipes for streams, abort, presign, layers, batch deletion, Copier, async I/O, and the blocking core.
    • Roadmap — completed Phase 5 slices and the remaining release gates.

    #Deliberate limits

    • Native source builds enable memory, fs, and s3; browser JS builds enable memory, opfs, and s3. GCS, Azure Blob, WebDAV, and other OpenDAL services are not compiled in.
    • delete_many is all-or-error and can have partial remote effects; it does not fabricate ordered per-path results or promise atomicity.
    • Copier copies one object between two paths on the same Operator. It is not recursive and cannot bridge two operators or services.
    • ReadStream.chunk_size hard-bounds each returned value and binding copy, but OpenDAL or a backend may provide and retain one larger raw buffer internally.
    • Suffix ranges require capability.can_read_suffix(); the binding does not emulate suffix reads with a preliminary stat.
    • The portable async slice covers whole writes and reads, bounded read streams, and chunked writers. Whole-object buffers are limited to 64 MiB and stream and writer chunks to 256 KiB on both targets. Native async stat/list/delete/copy/presign and public task handles remain later work; the JavaScript target additionally exposes its capability-checked Promise operations and stateful listers.
    • Retry, timeout, and concurrency limits are never implicit. Logging, tracing, metrics exporters, and custom callback layers are not exposed.
    • Standard artifacts are published for v0.2.0. Intel macOS, Windows, and musl Linux are not advertised; a Rust-only build is not treated as MoonBit host support.

    Passing an arbitrary scheme does not install a backend. ABI feature presence, selected-profile services, and a backend's operation capabilities are separate checks; unsupported services and operations raise OpenDalError instead of silently falling back.

    #Upstream references

    The organization of these guides follows Apache OpenDAL's official Node.js binding documentation while keeping the smaller MoonBit contracts explicit:

    OpenDalError

    pub suberror OpenDalError {
    OpenDalError(ErrorInfo)
    } derive(Eq,
    Debug
    )

    The checked error effect raised by all fallible OpenDAL operations.

    OpenDalError::from_error

    fn OpenDalError::from_error(error : Error) -> OpenDalError?

    Recover a structured OpenDAL error from MoonBit's target-neutral Error type. Async catch clauses receive Error, so this conversion preserves the same inspection path on native and JavaScript targets.

    OpenDalError::info

    fn OpenDalError::info(self : OpenDalError) -> ErrorInfo

    Return the structured context carried by this OpenDAL error.

    OpenDalError::is_persistent

    fn OpenDalError::is_persistent(self : OpenDalError) -> Bool

    Return whether OpenDAL classified the failure as persistent. This does not by itself make an operation safe to retry.

    OpenDalError::is_temporary

    fn OpenDalError::is_temporary(self : OpenDalError) -> Bool

    Return whether OpenDAL classified the failure as temporary. This does not by itself make an operation safe to retry.

    OpenDalError::kind

    fn OpenDalError::kind(self : OpenDalError) -> ErrorKind

    Return the stable error category.

    OpenDalError::status

    fn OpenDalError::status(self : OpenDalError) -> ErrorStatus

    Return OpenDAL's retry-status classification.

    AsyncOperator

    pub struct AsyncOperator {
    // private fields
    }

    An asynchronous view of an Operator.

    The view shares the configured operator but exposes only operations backed by OpenDAL's asynchronous API. Creating a view performs no I/O.

    AsyncOperator::close

    fn AsyncOperator::close(self : AsyncOperator) -> Unit

    Release this asynchronous operator. Closing more than once is harmless. Finish or close every child resource and await in-flight calls first; behavior of outstanding work after parent close is not portable.

    AsyncOperator::new

    async fn AsyncOperator::new(scheme : StringView, config? : Map[String, String]) -> AsyncOperator

    Construct the target's OpenDAL operator behind one portable asynchronous entry point.

    Native construction completes immediately; the JavaScript target performs its embedded runtime bootstrap. Call sites remain identical because both implementations are exposed as MoonBit async fn.

    AsyncOperator::open_read_stream

    async fn AsyncOperator::open_read_stream(self : AsyncOperator, path : StringView, range? : ByteRange, chunk_size? : Int, version? : StringView, if_match? : StringView, if_none_match? : StringView) -> AsyncReadStream

    Open an output-bounded asynchronous sequential read stream. chunk_size bounds each returned value and binding copy, not a raw backend buffer. It must be positive and no larger than the portable 256 KiB transfer limit. Suffix ranges require the underlying Operator's native capability.

    AsyncOperator::open_writer

    async fn AsyncOperator::open_writer(self : AsyncOperator, path : StringView, append? : Bool, content_type? : StringView, content_disposition? : StringView, content_encoding? : StringView, cache_control? : StringView, if_match? : StringView, if_none_match? : StringView) -> AsyncWriter

    Open an asynchronous chunked writer. Finalization never commits an open writer implicitly.

    AsyncOperator::read

    async fn AsyncOperator::read(self : AsyncOperator, path : StringView, range? : ByteRange, version? : StringView, if_match? : StringView, if_none_match? : StringView) -> Bytes

    Read one path or byte range into an owned Bytes value without blocking the MoonBit scheduler. Cancellation requests native cancellation; storage side effects already performed by the backend are not rolled back. Suffix ranges require the underlying Operator's native suffix capability. The portable whole-object result limit is 64 MiB; use a read stream for larger values.

    AsyncOperator::write

    async fn AsyncOperator::write(self : AsyncOperator, path : StringView, data : BytesView, append? : Bool, content_type? : StringView, content_disposition? : StringView, content_encoding? : StringView, cache_control? : StringView, if_match? : StringView, if_none_match? : StringView) -> Metadata

    Write an entire byte view without blocking the MoonBit scheduler.

    This portable convenience method is implemented in terms of the native asynchronous writer, preserving cancellation and commit semantics rather than calling the synchronous whole-object API from an async function. Input is limited to 64 MiB and split into 256 KiB Writer calls.

    AsyncReadStream

    pub struct AsyncReadStream {
    // private fields
    }

    An output-bounded asynchronous cursor over one object or byte range.

    A stream admits one operation at a time. Cancelling an in-flight next makes the stream terminal, because the cursor position may have advanced.

    AsyncReadStream::close

    fn AsyncReadStream::close(self : AsyncReadStream) -> Unit

    Release the cursor early. Closing more than once is harmless.

    AsyncReadStream::next

    async fn AsyncReadStream::next(self : AsyncReadStream) -> Bytes?

    Return the next owned chunk, or None after a stable end-of-stream.

    AsyncWriter

    pub struct AsyncWriter {
    // private fields
    }

    An asynchronous chunked writer.

    A writer admits one operation at a time. Cancelling an in-flight write, finish, or abort makes it terminal because remote commit status may be unknown.

    AsyncWriter::abort

    async fn AsyncWriter::abort(self : AsyncWriter) -> Unit

    Discard an unfinished write. A successful abort is idempotent.

    AsyncWriter::finish

    async fn AsyncWriter::finish(self : AsyncWriter) -> Metadata

    Commit all chunks and return the resulting metadata. The first finish attempt is terminal whether it succeeds, raises, or is cancelled.

    AsyncWriter::write

    async fn AsyncWriter::write(self : AsyncWriter, chunk : BytesView) -> Unit

    Write one complete chunk of at most 256 KiB. The selected byte view is copied before native work begins.

    ByteRange

    pub(all) enum ByteRange {
    Full
    From(offset~ : UInt64)
    Range(offset~ : UInt64, length~ : UInt64)
    Suffix(length~ : UInt64)
    } derive(Eq,
    Debug
    )

    An independent byte range for whole-object or random-access reads. The length field is a byte count, not an end offset. Suffix requires the selected backend's native suffix capability.

    Capability

    pub type Capability

    Capability is an immutable external snapshot of the ABI capability words.

    Capability::can_copy

    fn Capability::can_copy(self : Capability) -> Bool

    Return whether server-side copy is available through this binding.

    Capability::can_create_dir

    fn Capability::can_create_dir(self : Capability) -> Bool

    Return whether directory creation is available through this binding.

    Capability::can_delete

    fn Capability::can_delete(self : Capability) -> Bool

    Return whether deletion is available through this binding.

    Capability::can_list

    fn Capability::can_list(self : Capability) -> Bool

    Return whether prefix listing is available through this binding.

    Capability::can_list_recursive

    fn Capability::can_list_recursive(self : Capability) -> Bool

    Return whether recursive prefix listing is available.

    Capability::can_list_with_limit

    fn Capability::can_list_with_limit(self : Capability) -> Bool

    Return whether the backend accepts listing limit hints.

    Capability::can_list_with_start_after

    fn Capability::can_list_with_start_after(self : Capability) -> Bool

    Return whether the backend accepts listing start-after hints.

    Capability::can_presign_read

    fn Capability::can_presign_read(self : Capability) -> Bool

    Return whether read requests can be presigned through this binding.

    Capability::can_presign_stat

    fn Capability::can_presign_stat(self : Capability) -> Bool

    Return whether stat requests can be presigned through this binding.

    Capability::can_presign_write

    fn Capability::can_presign_write(self : Capability) -> Bool

    Return whether write requests can be presigned through this binding.

    Capability::can_read

    fn Capability::can_read(self : Capability) -> Bool

    Return whether whole-object reads are available through this binding.

    Capability::can_read_suffix

    fn Capability::can_read_suffix(self : Capability) -> Bool

    Return whether the selected backend natively supports suffix ranges. The binding does not emulate suffix reads with a preliminary stat.

    Capability::can_rename

    fn Capability::can_rename(self : Capability) -> Bool

    Return whether native rename is available through this binding.

    Capability::can_stat

    fn Capability::can_stat(self : Capability) -> Bool

    Return whether metadata lookup is available through this binding.

    Capability::can_write

    fn Capability::can_write(self : Capability) -> Bool

    Return whether whole-object writes are available through this binding.

    Capability::can_write_append

    fn Capability::can_write_append(self : Capability) -> Bool

    Return whether append mode is supported for writes through this binding.

    Capability::delete_max_size

    fn Capability::delete_max_size(self : Capability) -> Int?

    Return the backend's per-request batch-delete size hint, when available.

    This is distinct from Operator::delete_many's total binding input ceiling. Values above MoonBit's positive Int range are reported as Int::MAX.

    Copier

    pub struct Copier {
    // private fields
    }

    A managed, same-Operator copy of one object.

    This resource is neither recursive nor cross-service. Its finalizer only frees native state; it never reports completion or successful abort.

    Copier::abort

    fn Copier::abort(self : Copier) -> Unit raise OpenDalError

    Abort an unfinished copy.

    A successful abort is idempotent. Aborting a completed, finished, or failed Copier raises ResourceClosed; successful abort does not promise rollback of remote effects already made visible.

    Copier::finish

    fn Copier::finish(self : Copier) -> Metadata raise OpenDalError

    Drive any remaining copy steps and return destination metadata.

    The first finish failure is terminal.

    Copier::next

    fn Copier::next(self : Copier) -> UInt64? raise OpenDalError

    Advance one upstream copy step.

    Some(bytes) is that step's byte-count delta. None is a stable completed marker until finish consumes the retained destination metadata. A native failure is terminal.

    Entry

    pub struct Entry {
    path : String
    name : String
    metadata : Metadata
    } derive(Eq,
    Debug
    )

    A path and its possibly-partial metadata returned by a list operation.

    EntryMode

    pub enum EntryMode {
    File
    Directory
    Unknown
    } derive(Eq,
    Debug
    )

    Identifies whether an entry is a file, directory, or unknown object kind.

    ErrorInfo

    pub struct ErrorInfo {
    kind : ErrorKind
    status : ErrorStatus
    message : String
    operation : Operation
    path : String?
    destination_path : String?
    } derive(Eq,
    Debug
    )

    Structured context attached to a storage failure.

    ErrorKind

    pub enum ErrorKind {
    Unexpected
    Unsupported
    ConfigInvalid
    NotFound
    PermissionDenied
    IsADirectory
    NotADirectory
    AlreadyExists
    RateLimited
    IsSameFile
    ConditionNotMatch
    RangeNotSatisfied
    InvalidArgument
    ResourceClosed
    BufferTooLarge
    AbiMismatch
    UnknownKind(Int, String)
    } derive(Eq,
    Debug
    )

    Stable error categories exposed by the MoonBit binding.

    ErrorStatus

    pub enum ErrorStatus {
    Permanent
    Temporary
    Persistent
    UnknownStatus(Int)
    } derive(Eq,
    Debug
    )

    OpenDAL's retry classification for an operation failure.

    Lister

    pub struct Lister {
    // private fields
    }

    Safe lister wrapper retaining the prefix used for error context.

    Lister::close

    fn Lister::close(self : Lister) -> Unit

    Release listing resources early. Closing more than once is harmless.

    Lister::next

    fn Lister::next(self : Lister) -> Entry? raise OpenDalError

    Return the next entry, None at end-of-stream, or raise on failure. End-of-stream is stable. An I/O failure is terminal.

    Metadata

    pub struct Metadata {
    mode : EntryMode
    content_length : UInt64
    is_current : Bool?
    is_deleted : Bool
    cache_control : String?
    content_disposition : String?
    content_encoding : String?
    content_md5 : String?
    content_type : String?
    etag : String?
    last_modified : Timestamp?
    version : String?
    } derive(Eq,
    Debug
    )

    Read-only metadata snapshot associated with one operation context.

    Metadata::is_dir

    fn Metadata::is_dir(self : Metadata) -> Bool

    Return true when metadata describes a directory.

    Metadata::is_file

    fn Metadata::is_file(self : Metadata) -> Bool

    Return true when metadata describes a file.

    Operation

    pub enum Operation {
    NewOperator
    Check
    Exists
    CreateDir
    Read
    Write
    Stat
    Delete
    List
    Copy
    Rename
    } derive(Eq,
    Debug
    )

    The operation being attempted when an error occurred.

    Operator

    pub type Operator

    Native operator storage is a MoonBit external object finalized by the C stub. Its payload contains only project-owned C ABI handles.

    Operator::as_async

    fn Operator::as_async(self : Operator) -> AsyncOperator

    Create a lightweight asynchronous view that shares this Operator.

    Operator::check

    fn Operator::check(self : Operator) -> Unit raise OpenDalError

    Verify that the operator can perform OpenDAL's check operation.

    Operator::close

    fn Operator::close(self : Operator) -> Unit

    Release this native operator early. Closing more than once is harmless. Operations attempted after close fail through the native binding boundary.

    Operator::copy

    fn Operator::copy(self : Operator, source : StringView, destination : StringView) -> Metadata raise OpenDalError

    Copy one object with the backend's native copy operation and return the destination metadata. This is never emulated with read plus write.

    Operator::create_dir

    fn Operator::create_dir(self : Operator, path : StringView) -> Unit raise OpenDalError

    Create a directory recursively. A directory path must end with /.

    Operator::delete

    fn Operator::delete(self : Operator, path : StringView, version? : StringView, recursive? : Bool) -> Unit raise OpenDalError

    Delete a path. Deleting a missing path is successful.

    Operator::delete_many

    fn Operator::delete_many(self : Operator, paths : ArrayView[String]) -> Unit raise OpenDalError

    Delete multiple paths through OpenDAL's high-level deleter.

    The binding copies and validates all paths before starting. Empty input succeeds without calling the backend. Native ABI representability checks and the backend's batch hint remain distinct from public API policy. A returned error can follow partial remote effects; this all-or-error API does not report per-path outcomes or promise input ordering, uniqueness, or atomicity.

    Operator::exists

    fn Operator::exists(self : Operator, path : StringView) -> Bool raise OpenDalError

    Check whether a path exists. Only NotFound becomes false; all other failures remain errors.

    Operator::info

    fn Operator::info(self : Operator) -> OperatorInfo

    Return a read-only information and capability snapshot.

    Operator::list

    fn Operator::list(self : Operator, path : StringView, recursive? : Bool, limit? : UInt64, start_after? : StringView) -> Array[Entry] raise OpenDalError

    Materialize a prefix listing into memory. The optional limit is a backend request hint rather than a total-result bound.

    Operator::new

    fn Operator::new(scheme : StringView, config? : Map[String, String]) -> Operator raise OpenDalError

    Construct an operator from a service scheme and configuration map. The map is copied and is never mutated or retained by reference.

    Operator::open_copier

    fn Operator::open_copier(self : Operator, source : StringView, destination : StringView) -> Copier raise OpenDalError

    Open an incremental copy between two paths on this Operator.

    The returned Copier owns the native operator state it needs and may outlive this Operator.

    Operator::open_lister

    fn Operator::open_lister(self : Operator, path : StringView, recursive? : Bool, limit? : UInt64, start_after? : StringView) -> Lister raise OpenDalError

    Open a fallible prefix-listing cursor. The returned resource should be closed when iteration stops before end-of-stream.

    Operator::open_read_stream

    fn Operator::open_read_stream(self : Operator, path : StringView, range? : ByteRange, chunk_size? : Int, version? : StringView, if_match? : StringView, if_none_match? : StringView) -> ReadStream raise OpenDalError

    Open a bounded sequential read stream.

    chunk_size is fixed for the lifetime of the stream and defaults to one MiB. It bounds each returned Bytes value and binding copy, not a raw backend buffer. It must be positive and fit the native output ceiling. The returned stream owns its cursor and may outlive this Operator. Suffix ranges require self.info().capability.can_read_suffix().

    Operator::open_reader

    fn Operator::open_reader(self : Operator, path : StringView, version? : StringView, if_match? : StringView, if_none_match? : StringView) -> Reader raise OpenDalError

    Open a random-access reader. Reads on the returned value are independent; it does not maintain an implicit cursor.

    Operator::open_writer

    fn Operator::open_writer(self : Operator, path : StringView, append? : Bool, content_type? : StringView, content_disposition? : StringView, content_encoding? : StringView, cache_control? : StringView, if_match? : StringView, if_none_match? : StringView) -> Writer raise OpenDalError

    Open a chunked writer. The returned resource reports completion only after finish succeeds; finalization never finishes an open writer implicitly.

    Operator::presign_read

    fn Operator::presign_read(self : Operator, path : StringView, expires_in_seconds~ : UInt64, range? : ByteRange, version? : StringView, if_match? : StringView, if_none_match? : StringView) -> PresignedRequest raise OpenDalError

    Create a presigned HTTP read request.

    The returned URI and headers can contain bearer-equivalent signing material. Avoid logging or snapshotting them. Header order, duplicate names, and binary values are preserved.

    Operator::presign_stat

    fn Operator::presign_stat(self : Operator, path : StringView, expires_in_seconds~ : UInt64, version? : StringView, if_match? : StringView, if_none_match? : StringView) -> PresignedRequest raise OpenDalError

    Create a presigned HTTP metadata request.

    The returned URI and headers can contain bearer-equivalent signing material. Avoid logging or snapshotting them.

    Operator::presign_write

    fn Operator::presign_write(self : Operator, path : StringView, expires_in_seconds~ : UInt64, append? : Bool, content_type? : StringView, content_disposition? : StringView, content_encoding? : StringView, cache_control? : StringView, if_match? : StringView, if_none_match? : StringView) -> PresignedRequest raise OpenDalError

    Create a presigned HTTP write request.

    The returned URI and headers can contain bearer-equivalent signing material. Avoid logging or snapshotting them. The caller supplies the request body when executing the snapshot.

    Operator::read

    fn Operator::read(self : Operator, path : StringView, range? : ByteRange, version? : StringView, if_match? : StringView, if_none_match? : StringView) -> Bytes raise OpenDalError

    Read a path or byte range into one owned Bytes value. Suffix ranges require self.info().capability.can_read_suffix().

    Operator::rename

    fn Operator::rename(self : Operator, source : StringView, destination : StringView) -> Unit raise OpenDalError

    Rename one object with the backend's native rename operation. This is never emulated with copy plus delete.

    Operator::s3

    fn Operator::s3(bucket : StringView, region~ : StringView, root? : StringView, endpoint? : StringView, auth? : S3Auth, virtual_host_style? : Bool) -> Operator raise OpenDalError

    Construct an S3 operator with a typed, secret-safe authentication policy. Omitting auth selects the standard AWS credential chain.

    Operator::stat

    fn Operator::stat(self : Operator, path : StringView, version? : StringView, if_match? : StringView, if_none_match? : StringView) -> Metadata raise OpenDalError

    Fetch metadata for a path. Optional conditions are copied at the native call boundary.

    Operator::with_concurrency_limit

    fn Operator::with_concurrency_limit(self : Operator, operation_limit~ : UInt, http_request_limit? : UInt) -> Operator raise OpenDalError

    Return a new operator with explicit operation and optional HTTP concurrency limits.

    operation_limit bounds concurrent OpenDAL operations. For body-style resources, including Reader-created streams, Writers, Listers, Deleters, and Copiers, a permit remains held for the body lifetime. When provided, http_request_limit separately bounds HTTP requests and its permit remains held until the response body is dropped.

    The original operator and resources already opened from it are unchanged. Compose policies as timeout, then retry, then concurrency limit. This layer can be added only once and is always outermost; timeout or retry cannot be added afterward.

    Operator::with_retry

    fn Operator::with_retry(self : Operator, max_retries~ : UInt, min_delay_millis? : UInt64, max_delay_millis? : UInt64, jitter? : Bool) -> Operator raise OpenDalError

    Return a new operator with explicit retry policy.

    max_retries counts attempts after the initial request. Retries are opt-in and can replay stateful Writer operations after an uncertain remote commit; this method does not promise exactly-once writes or safe append replay. Add timeout before retry when composing both policies. The native layer rejects duplicate retry layers and the unsafe reverse composition.

    Operator::with_timeout

    fn Operator::with_timeout(self : Operator, operation_timeout_millis~ : UInt64, io_timeout_millis~ : UInt64) -> Operator raise OpenDalError

    Return a new operator with explicit control-operation and I/O timeouts.

    The original operator and resources already opened from it are unchanged. When composing timeout with retry, add timeout first and retry second so each retry attempt is inside the timeout budget. The native layer rejects duplicate timeout layers and the unsafe reverse composition.

    Operator::write

    fn Operator::write(self : Operator, path : StringView, data : BytesView, append? : Bool, content_type? : StringView, content_disposition? : StringView, content_encoding? : StringView, cache_control? : StringView, if_match? : StringView, if_none_match? : StringView) -> Metadata raise OpenDalError

    Write an entire byte view and return the resulting metadata. Only the selected view is copied across the native boundary.

    OperatorInfo

    pub struct OperatorInfo {
    scheme : String
    root : String
    name : String
    capability : Capability
    }

    Read-only information about one configured operator.

    PresignedHeader

    pub struct PresignedHeader {
    name : String
    value : Bytes
    } derive(Eq)

    One owned HTTP header from a presigned request.

    Header values remain bytes because a valid HTTP field value is not required to be UTF-8. This type deliberately has no Debug or Show implementation because signing material can appear in header values.

    PresignedRequest

    pub struct PresignedRequest {
    http_method : String
    uri : String
    headers : Array[PresignedHeader]
    } derive(Eq)

    A fully owned HTTP request snapshot produced by an OpenDAL presign operation.

    Header order and duplicate names are preserved. The URI and headers can contain bearer-equivalent signing material, so this type deliberately has no Debug or Show implementation.

    ReadStream

    pub struct ReadStream {
    // private fields
    }

    An output-bounded sequential cursor over one object or byte range.

    Each successful next returns an owned chunk no larger than the chunk_size selected when the stream was opened. None is a stable end-of-stream marker.

    ReadStream::close

    fn ReadStream::close(self : ReadStream) -> Unit

    Release the cursor early. Closing more than once is harmless.

    ReadStream::next

    fn ReadStream::next(self : ReadStream) -> Bytes? raise OpenDalError

    Return the next owned chunk, None at end-of-stream, or raise on failure.

    End-of-stream is stable. A stream failure is terminal, and later calls raise ResourceClosed.

    Reader

    pub struct Reader {
    // private fields
    }

    Safe random-access reader retaining the path used for error context.

    Reader::close

    fn Reader::close(self : Reader) -> Unit

    Release reader resources early. Closing more than once is harmless.

    Reader::read

    fn Reader::read(self : Reader, range : ByteRange) -> Bytes raise OpenDalError

    Read one independent range into an owned Bytes value. Ordinary read errors leave the Reader open for another range. Suffix ranges require the originating Operator's suffix capability.

    S3Auth

    pub struct S3Auth {
    // private fields
    }

    Authentication policy for an S3 operator. Credential material is opaque and has no debug or display representation.

    S3Auth::assume_role

    fn S3Auth::assume_role(role_arn~ : StringView, source? : S3CredentialSource, external_id? : StringView, role_session_name? : StringView, duration_seconds? : UInt64) -> S3Auth raise OpenDalError

    Assume an IAM role using either the standard credential chain or explicit static source credentials. Omitting source selects the standard chain.

    S3Auth::default_chain

    fn S3Auth::default_chain(disable_ec2_metadata? : Bool) -> S3Auth

    Use the standard AWS credential chain. EC2 instance metadata remains available unless explicitly disabled.

    S3Auth::static_credentials

    fn S3Auth::static_credentials(access_key_id~ : StringView, secret_access_key~ : StringView, session_token? : StringView) -> S3Auth raise OpenDalError

    Use an explicit access-key pair, with an optional session token.

    S3Auth::unsigned

    fn S3Auth::unsigned() -> S3Auth

    Send unsigned S3 requests. This is intended for public buckets or custom endpoints that explicitly allow anonymous access.

    S3CredentialSource

    pub struct S3CredentialSource {
    // private fields
    }

    Credentials that may be used directly or as the source for an S3 assume-role request. Values are copied when the source is constructed.

    S3CredentialSource::default_chain

    fn S3CredentialSource::default_chain(disable_ec2_metadata? : Bool) -> S3CredentialSource

    Use the standard AWS credential chain. EC2 instance metadata remains available unless explicitly disabled.

    S3CredentialSource::static_credentials

    fn S3CredentialSource::static_credentials(access_key_id~ : StringView, secret_access_key~ : StringView, session_token? : StringView) -> S3CredentialSource raise OpenDalError

    Use an explicit access-key pair, with an optional session token.

    Timestamp

    pub struct Timestamp {
    unix_seconds : Int64
    nanoseconds : Int
    } derive(Eq,
    Debug
    )

    A UTC instant represented without imposing a calendar/time-zone package. nanoseconds is always in the range 0 through 999,999,999 for values produced by this package.

    Writer

    pub struct Writer {
    // private fields
    }

    Safe chunked writer retaining the path used for error context.

    Writer::abort

    fn Writer::abort(self : Writer) -> Unit raise OpenDalError

    Discard an unfinished write. A successful abort is idempotent; after any other terminal outcome this method raises ResourceClosed.

    Writer::finish

    fn Writer::finish(self : Writer) -> Metadata raise OpenDalError

    Commit all chunks and return the resulting metadata. The first finish attempt is terminal whether it succeeds or raises.

    Writer::write

    fn Writer::write(self : Writer, chunk : BytesView) -> Unit raise OpenDalError

    Write one complete chunk. Any native write failure is terminal for this Writer; later calls raise ResourceClosed.