Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Memona plugins

Plugins connect Memona to additional filesystems through a shared API. The app and its folder agents use the same connection service and permission checks.

How it works

A plugin is a portable WebAssembly component. Memona’s Rust backend hosts it using Wasmtime and calls the filesystem functions described by WIT. WIT defines the contract; WASI provides selected system interfaces. The backend supplies network access while retaining host-enforced transport and resource limits.

Plugin authors can use the Rust SDK without copying Memona’s WIT files into their own repository. There is no Python or JavaScript backend interpreter. The same installed backend serves both the native app window and browser clients connected to it; plugins do not depend on a browser tab remaining open.

Initial scope

The initial API covers filesystem providers, connection configuration and agent file tools. WebDAV and IPFS integrations are planned provider implementations; this release does not bundle them. The repository includes a test component that demonstrates the contract.

Custom viewers and editors using Web Components are a future extension point. Version 1 packages do not execute frontend JavaScript or install scripts. Remote offline synchronization is also outside this initial API delivery.

Memona keeps its existing folders-as-pages model. Plugins do not introduce a mandatory vault structure.

Using plugins

Open Plugins from Memona’s menu. The dialog has three sections:

  • Browse searches the public catalog and shows package details.
  • Installed manages installed versions and enabled state.
  • Connections configures each provider and its agent permissions.

Install and update

Select a catalog entry to inspect the publisher, version and description. Choose Install to download that exact release. Memona validates the downloaded package and its digest before activation. You do not need a publisher account to browse or install.

Updates are explicit. A failed update leaves the previous installed version in place. Installed plugins can contact public and private network services. Agent access remains controlled by each connection’s settings.

Disabling a plugin stops its connections and prevents new operations. Removing a plugin does not delete files stored on a remote service. If the catalog is unavailable, installed plugins can still be managed; remote operations still need access to their configured remote service.

Connections and agents

A provider can have several connections with separate configuration. Set agent access independently for each connection:

SettingWhat Memona’s agent file tool can do
OffThe connection is not available to agents.
Read onlyInspect folders and read files.
Read and writeRead and request supported changes.

The provider may itself be read-only. Granting write access cannot add an operation that the provider does not support. Agent grants apply to Memona’s remote-file tool; they do not change what an external agent’s independent shell or local filesystem tools can access.

Enter the server address and credentials in the provider’s connection fields. There is no second network allowlist to configure. Plugins may contact public, LAN, VPN, link-local and loopback addresses. A plugin declares its protocol’s socket ports, and Memona applies them automatically.

Credentials belong to a connection. Secret fields are kept in backend memory and are not shown back to the frontend or written to the connection file. After restarting the backend, enter required secrets again before reconnecting.

Publishing

Use the publisher link to open plugin.memona.io. Publishing and email verification happen there. Installation happens inside Memona; there is no custom install-link protocol.

The website also provides plugin guides, publisher profiles and sorting by updates, downloads or likes. You can sign in to like a plugin without becoming a publisher. Downloads count package requests rather than installed copies or individual people. Daily activity uses UTC and distinguishes dates before tracking began from dates with zero downloads.

Agent access

Installed filesystem providers share one Memona agent tool, remote_files. Enable access for each connection in Plugins → Connections. New connections default to Off. Read only permits browsing and reading; Read and write also permits supported changes.

An agent first discovers connections:

{"operation": "connections"}

Only connections with an enabled plugin and an agent grant appear. Use the returned connection ID for subsequent calls:

{
  "operation": "list",
  "connectionId": "the-returned-connection-id",
  "path": "/",
  "cursor": null,
  "limit": 100
}

To read part of a file:

{
  "operation": "read",
  "connectionId": "the-returned-connection-id",
  "path": "/notes.md",
  "offset": 0,
  "length": 65536
}

File bytes are JSON arrays of integers from 0 through 255. A read includes an opaque revision when the provider supports it and an end-of-file flag. Continue with the next offset to read a larger file. Each call transfers at most 1 MiB.

Changing a file

A write replaces the entire file. Always choose a condition:

ConditionBehavior
{"kind":"createOnly"}Fail if a file already exists.
{"kind":"ifMatch","revision":"opaque-token"}Replace only the revision you read.
{"kind":"overwrite"}Explicitly replace the current contents.

Conditional replacement requires provider support. An unsupported condition fails; the host never silently changes it to overwrite. A file larger than the write limit cannot be saved with this API version. Splitting it into multiple writes would repeatedly replace the file, not append chunks.

If a mutation reports outcomeUnknown, inspect the remote state before deciding whether to retry: the service may have completed it before the response was lost.

These resources are connection-relative paths, not operating-system mounts. An agent’s ordinary shell and local file tools do not automatically access them. Changing the grant or disabling the plugin affects subsequent calls and cancels active work for that connection.

Build a plugin

The initial SDK targets Rust and WASI 0.2 components. Install the component target:

rustup target add wasm32-wasip2

The reference implementation uses Rust 1.98. Plugin source can use compatible Rust releases, but its generated component must satisfy the supported WIT API. Native subprocess, OS-specific and unrestricted networking crates are not automatically available inside a component.

Start with the SDK

The SDK lives at plugin_system/sdk in the Memona repository. Until a crates.io release is published, use a checked-out, pinned Memona revision and a path dependency:

[package]
name = "my-memona-plugin"
version = "0.1.0"
edition = "2024"

[lib]
crate-type = ["cdylib"]

[dependencies]
memona-plugin-sdk = { path = "../memona/plugin_system/sdk" }

The path is relative to your own Cargo.toml; adjust it to your checkout. Pin the checkout revision so your build does not silently pick up an API change.

The SDK includes the canonical WIT and generated Rust types. Implement its Guest trait and invoke its export! macro for your implementation type. You do not need wasm-bindgen, wasm-pack, or WIT copies in your plugin repository. cargo doc also exposes the generated Rust API.

struct MyProvider;

// Implement every method of memona_plugin_sdk::Guest for MyProvider.
// Unsupported optional operations return ErrorCode::Unsupported.
memona_plugin_sdk::export!(MyProvider);

This short excerpt shows registration, not a complete implementation. The full buildable example is plugin_system/test-component/src/lib.rs. It is a test fixture, not a WebDAV or IPFS client. From a Memona checkout, build it with:

cargo build --manifest-path plugin_system/Cargo.toml \
  -p memona-plugin-test-component --target wasm32-wasip2 --release

Build your own plugin with:

cargo build --release --target wasm32-wasip2

Call the host

Use the SDK’s generated host interface for network requests. For example, this helper retrieves a bounded HTTP response through the connection’s permissions:

use memona_plugin_sdk::memona::filesystem::host;

pub fn get_bytes(url: &str) -> Result<Vec<u8>, host::HostError> {
    let response = host::http(&host::Request {
        method: "GET".into(),
        url: url.into(),
        headers: Vec::new(),
        body: Vec::new(),
    })?;
    if !(200..300).contains(&response.status) {
        return Err(host::HostError::Unavailable);
    }
    Ok(response.body)
}

Map HTTP statuses to appropriate filesystem errors in a real provider. Supply authentication through request headers using connection configuration; do not hard-code tokens. The host resolves and pins addresses on every request and on every redirect it follows.

Nothing crosses whole. A request body is pushed in pieces of at most 1 MiB and a response body is pulled the same way, so a file of any size moves without either side holding it. The same shape governs reader and writer, which is how a provider serves a file larger than one call allows.

A protocol that is not HTTP uses connect for a TCP stream or bind for a datagram socket, each on a package-declared port. The host resolves and pins DNS and can start TLS so certificate checking stays outside the guest.

Prepare a release

Copy the resulting .wasm component to plugin.wasm, write manifest.json, and ZIP the files at the archive root. Name the archive with a .memona-plugin suffix. A directory wrapping the files inside the ZIP is not accepted.

Use the filesystem behavior guide to handle revisions, unsupported operations and mutation failures correctly. Before publishing, exercise your provider against its real service and test lost connections.

Package format

A .memona-plugin package is a ZIP archive with these root entries:

manifest.json   required
plugin.wasm     required WebAssembly component
README.md       optional UTF-8 text
LICENSE         optional UTF-8 text
icon.png        optional PNG

Version 1 rejects other entries, duplicate paths, directories, symlinks, encrypted archives and paths that could escape the archive root. There are no install hooks or executable frontend assets.

Guide and icon

Include a root-level README.md to provide the guide on the plugin’s public page. Write UTF-8 Markdown and explain setup, required services, connection fields, supported operations and limitations. Keep credentials and other private information out of the guide. A release without a README shows a missing-guide message; the store does not invent documentation from its manifest.

The website renders headings, lists, links, code and tables as selectable text. Raw HTML is disabled and rendered content is sanitized. Links may use HTTP, HTTPS or mailto; remote images become links or descriptive text instead of loading a third-party image. Use fenced code blocks for examples and ordinary links for external diagrams or screenshots.

An optional root-level icon.png supplies the icon on catalog cards and the plugin page. It must be a PNG no larger than 1 MiB. A missing icon uses the plugin’s initial. The store serves the validated package asset from its own origin; a manifest cannot point the icon at another server.

README and icon belong to an immutable release. Publish a new version to change them. Both are extracted through the isolated package validator, including when the store first reads metadata from an older release. Assets and guides from withdrawn releases are unavailable through public release routes.

Manifest

{
  "schemaVersion": 2,
  "id": "your-publisher/my-provider",
  "name": "My filesystem",
  "version": "0.1.0",
  "apiVersion": "0.1.0",
  "description": "Connect to my filesystem service.",
  "license": "MIT",
  "entry": "plugin.wasm",
  "providers": [
    {
      "id": "files",
      "name": "My filesystem",
      "schemes": ["myfiles"],
      "configFields": [
        {"key": "endpoint", "label": "Service URL", "kind": "text", "required": true},
        {"key": "token", "label": "Access token", "kind": "password", "required": true}
      ]
    }
  ]
}

Replace the example publisher with your own. Your verified publisher account must own the publisher portion of the package ID.

FieldMeaning
schemaVersionManifest shape; new packages use 2.
idImmutable publisher/plugin identifier.
versionCanonical semantic release version.
apiVersionMemona plugin API version; currently 0.1.0.
entryMust be plugin.wasm in this format.
networkPortsDeclared port spans for sockets, as { "from": 21, "to": 21 }.
providersStable provider identities and declarative configuration fields.

Publisher/plugin/provider slugs use lowercase ASCII letters, digits and hyphens, begin and end with a letter or digit, and have at most 64 characters. Human names can use other languages. Configuration kind is text, password or boolean. Never place a credential in a manifest or a password default. Publishing rejects a member the catalog does not know, so a typo never ships, while an app older than a member ignores it, so a newer catalog never breaks an installed app.

Plugins can contact any public, LAN, VPN, link-local or loopback host through the host’s HTTP and socket services. There is no host allowlist or private network grant in the manifest or connection configuration. ENS or other name-resolution protocols can contact their RPC nodes and content gateways; the plugin implements resolution before making ordinary network requests.

Current Memona versions also read schema 1 packages, ignoring their obsolete host declarations. New publications use schema 2. The legacy catalog API keeps the old manifest shape for older apps; new clients use /api/v2.

An empty networkPorts list declares no sockets, which is every provider that speaks only HTTP. A protocol that negotiates its data channel at runtime, as FTP does, declares the span it may land in rather than one port. Memona applies these declarations automatically to each connection. At most 16 spans.

Limits and compatibility

ItemLimit
Compressed package32 MiB
Expanded archive total128 MiB
WASM component64 MiB
Manifest64 KiB
README or license256 KiB each
PNG icon1 MiB

The same validation runs on the store and in Memona. Components must implement the full provider interface, including optional-operation methods that may return unsupported, and import only supported host services.

Each published ID/version permanently identifies one byte sequence and SHA-256 digest. Correct a release by incrementing its version. Withdrawing a release prevents new catalog installations; it does not silently remove installed code.

Filesystem behavior

The generated reference lists exact names and types. This page explains the behavior expected across different remote services.

Connection and paths

Memona creates one component instance per connection. open receives the provider ID and that connection’s configuration and returns its capabilities. The host owns connection IDs; the plugin receives connection-relative paths.

/ is the connection root. Paths use / separators, cannot traverse above the root and must never be interpreted as local OS paths. File names are returned as names, not HTML. A listing is paginated with an opaque cursor and a bounded limit. Do not reuse a cursor across unrelated listing requests.

Read and revisions

stat identifies a file or directory and may return an opaque revision token. read takes an offset and maximum length and returns bytes, an optional revision and an end-of-file flag. Use bounded range reads rather than loading an entire remote file into guest memory. Do not silently truncate data while claiming EOF.

Revision values are provider-defined. They could be a service ETag or an immutable content identifier. Consumers compare them for equality; they must not parse them as timestamps or assume they are ordered.

Write and conflict handling

The initial write operation replaces a complete file within the host’s transfer limit. It is not an append or streaming-write operation. Large-file publishing must not be simulated by repeated calls that accidentally overwrite each other.

The caller chooses one of three conditions:

  • create-only: fail if the target already exists.
  • if-match(revision): replace only that revision atomically.
  • overwrite: replacement explicitly requested without a revision condition.

Only advertise conditional-write support if the remote service can enforce it. A read followed by an unconditional write is not an atomic conditional write. Return unsupported when you cannot honor the requested condition.

If a connection fails after a write or other mutation may have reached the server, report outcome-unknown. Do not retry automatically: the operation might already have succeeded. Consumers can inspect the remote state before deciding what to do next.

Read-only stores return unsupported for mutations. They still implement all exported methods so the component has a predictable shape. Write permission from the user never overrides a provider’s missing capability.

Changes and cleanup

Providers that support change polling advertise that capability. A poll returns a bounded batch and optional cursor; it must finish promptly. The initial API exposes explicit poll calls. A caller retains its cursor and decides when to poll again; there is no automatic watcher subscription in this version.

close releases provider-owned connection state. Timeouts, disable, disconnect, update or uninstall may terminate the instance even if cleanup cannot finish. Never rely on an eventual close callback to commit a pending write.

Errors

Return the closest typed error category. Host/UI messages are generic and localized. Do not put credentials into log messages. An unsupported operation, permission denial, missing file and version conflict are different outcomes; turning all of them into an internal error prevents useful recovery.

Permissions and lifecycle

Network and system services

The host provides bounded HTTP requests through the WIT host interface. Network access permits public, LAN, VPN, link-local and loopback addresses. Socket ports must be declared in the package. Redirects follow the same transport rules. A provider must not assume that compiling a native networking crate grants socket or process access.

WASI support is deliberately limited. The plugin does not inherit Memona’s environment variables, local directories, credentials for other connections or subprocess access. Clock/randomness and standard-library plumbing are supplied only as permitted by the host. Filesystem imports do not imply that local host directories are mounted into the component.

Keep declared socket ports as narrow as the service allows. Do not include tokens in URLs or diagnostics; use the connection’s secret fields.

Agent grants

Each connection is off, read-only, or read/write for Memona’s remote_files tool. The Rust host checks the current setting before discovery and every operation. Plugins cannot raise their own grants, and an agent’s permissive CLI mode cannot bypass them.

These controls do not sandbox the external agent’s independently available shell. An agent must use Memona’s tool to access a provider; virtual paths are not automatically mounted as system drives.

Resource limits and cancellation

Each guest instance has a 64 MiB linear-memory limit and a bounded execution budget. A plugin that loops forever or traps is stopped. Transfer sizes, queued work and operation duration are also bounded. Host I/O is asynchronous, but the WASI 0.2 guest interface can look synchronous to its Rust implementation.

Package validation and compilation use separate, short-lived workers with a 30-second deadline per job. The app shares a two-worker limit across both stages; the store permits two validation workers. Cancelling either stage kills and reaps its worker before the slot becomes available again. Only output from Memona’s own compiler worker can be loaded as compiled code; downloaded packages contain portable WASM components.

Worker memory is separate from the guest limit. Linux workers have a 2 GiB virtual-address-space ceiling; macOS workers receive 2 GiB beyond their startup mappings. Windows workers have a 2 GiB committed-memory ceiling. These are process allocation limits, not an identical resident-memory measurement on every OS.

Disabling or removing a plugin prevents new calls and cancels active work. Connection instances do not share mutable guest state or credentials. The backend may remain alive after windows close; all work ends when the backend itself exits.

Future frontend modules

A future Web Component runs in a browser context and has a different permission boundary. Serving JavaScript from a WASM component does not place that JavaScript inside the WASM sandbox. Version 1 does not execute frontend plugin modules.

Publish a release

  1. Open Account and enter your email address.
  2. Enter the 16-character sign-in code from your email to sign in.
  3. Claim a publisher name and prepare a package with that publisher in its ID.
  4. Upload your .memona-plugin package in the publisher dashboard.
  5. After automatic validation succeeds, the release appears in the public catalog.

Email is delivered through Resend. Codes expire after 15 minutes, have a limited number of attempts and can only be consumed once. Entering the code confirms sign-in; email scanners cannot consume it by following a link.

Signing in does not require a publisher name. Readers can like public plugins with a verified account and claim a publisher name later when they want to publish. Each account contributes at most one like to a plugin; clicking an active like removes it.

Public profile

Your publisher name is permanent and forms the first part of each plugin ID. After claiming it, edit your display name, biography and optional website in Account. Display names allow up to 80 characters, biographies 2,000 and website URLs 2,048. Websites must use HTTP or HTTPS.

Your public page at /publishers/your-publisher shows these fields, your joined date and public plugins. Your email address and account ID stay private. A plugin with no available release does not appear among your public plugins.

What validation checks

The store checks account ownership, archive structure and limits, the manifest, component validity, supported imports and the filesystem interface. It never runs a publisher’s component during validation. Memona repeats package and digest validation when installing.

Automatic validation is not a source-code review. Email verification confirms control of an address; it does not certify a developer’s identity or behavior.

Releases and updates

Versions are immutable. Upload a new semantic version for a fix, even if the old version has been withdrawn. Users select and install releases inside Memona’s Plugins dialog; website links do not automatically install code.

Describe connection requirements and supported operations clearly. Include license information and a README in the package. Do not embed private service credentials, publisher sessions or verification tokens.

Keep API compatibility separate from your plugin’s release number. A new plugin release can continue using the same Memona WIT API. A component requiring an unsupported API cannot be installed until Memona supports that contract.

Downloads and activity

Plugin pages show lifetime downloads and daily UTC activity. A download means an accepted package GET request whose artifact was successfully opened. It does not prove that the transfer finished or that Memona installed the plugin, and repeated requests from the same person count separately. HEAD requests, unavailable artifacts and withdrawn downloads do not increment the counters.

Lifetime and daily counters update together. Existing lifetime totals remain when daily tracking begins. Dates before tracking began are marked Not tracked; tracked dates with no requests show zero. The history endpoint supports 1–365 days and reports when tracking began. No historical downloads are invented to fill earlier dates.

World filesystem

Memona filesystem extension ABI 0.1.0, distributed as a WebAssembly component. Rust guests can target wasm32-wasip2. Selected WASI 0.2 CLI, clocks, random, IO and filesystem interfaces are allowed for the standard library, with empty arguments/environment, empty preopens, and discarded stdio. WASI sockets and HTTP imports are not allowed; networking uses the host interface.

  • Imports:
    • interface memona:filesystem/host@0.1.0
  • Exports:
    • interface memona:filesystem/provider@0.1.0

Import interface memona:filesystem/host@0.1.0

Host services scoped to the current connection. No ambient filesystem, environment, sockets, credentials, or network permissions are inherited.


Types

enum host-error

Stable failures without backend messages or credential-bearing URLs.

Enum Cases
  • denied
  • unavailable
  • invalid-input
  • cancelled
  • internal

enum log-level

Severity of a diagnostic event. The host may discard message contents.

Enum Cases
  • debug
  • info
  • warn
  • error

enum method

Every method the host will send. A verb outside this list cannot be spelled, so no plugin can smuggle one past the transport rules.

Enum Cases
  • get
  • head
  • post
  • put
  • patch
  • delete
  • propfind
  • proppatch
  • mkcol
  • copy
  • move
  • lock
  • unlock
  • report

record header

An HTTP header. Host-controlled transport headers cannot be overridden.

Record Fields
  • name: string
  • value: string

record request

Request head. At most 64 headers of 8 KiB each; the body is streamed.

Record Fields

record response

Response head. The body is read from the exchange that produced it.

Record Fields
  • status: u16
  • headers: list<header>

resource exchange

One HTTP request and its response, streamed in bounded chunks so a transfer is never held whole in memory. A body of any size crosses in pieces, which is what multipart uploads of at least 5 MiB require. Dropping the handle abandons the request.

resource tcp

One open TCP connection. Dropping the handle closes the socket, and the host closes every socket when the connection is disposed.

resource udp

One datagram socket connected to a single peer.

variant setting

A configuration value, typed as the package’s manifest declared it. A secret is never logged by the host and never leaves the connection.

Variant Cases
  • text: string
  • secret: string
  • toggle: bool

Functions

[method]exchange.push: func

Appends at most 1,048,576 bytes to the request body. Every push must land before respond.

Params
Return values

[method]exchange.respond: func

Ends the request body and waits for the response head. Calling it twice is invalid-input.

Params
Return values

[method]exchange.pull: func

Reads at most 1,048,576 bytes of the response body, after respond. An empty result means the body is complete.

Params
Return values

http: func

Begins a request to any HTTP or HTTPS host, including LAN and loopback addresses. Each redirect and DNS result is checked, and DNS is pinned. Cross-origin redirects remove request headers; HTTPS cannot downgrade. The host bounds total bytes per exchange, not buffer size.

Params
Return values

[method]tcp.read: func

Reads at most limit bytes, between 1 and 1,048,576. An empty result means the peer closed its side, not that data is pending.

Params
  • self: borrow<tcp>
  • limit: u32
Return values

[method]tcp.write: func

Writes at most 1,048,576 bytes and returns how many were accepted.

Params
  • self: borrow<tcp>
  • data: list<u8>
Return values

connect: func

Opens a socket to any host, including LAN and loopback addresses, on a package-declared port. The host resolves and pins DNS and starts TLS when asked. Ports negotiated at runtime, such as an FTP data channel, must be declared.

Params
  • host: string
  • port: u16
  • tls: bool
Return values

[method]udp.send: func

Sends one datagram of at most 65,507 bytes.

Params
  • self: borrow<udp>
  • data: list<u8>
Return values

[method]udp.receive: func

Receives one datagram of at most limit bytes. An empty result means none arrived inside the host’s wait, not that the peer left.

Params
  • self: borrow<udp>
  • limit: u32
Return values

bind: func

Connects a datagram socket under the same port rules as connect, for the few filesystem protocols that still need one.

Params
  • host: string
  • port: u16
Return values

config: func

Reads configuration or a session-only credential for this connection.

Params
  • key: string
Return values

log: func

Emits a diagnostic event. Never include secrets or private document data.

Params

Export interface memona:filesystem/provider@0.1.0


Types

type setting

setting

enum error-code

Stable operation failures. A mutation interrupted after dispatch can report outcome-unknown: inspect remote state before deciding to retry.

Enum Cases
  • not-found
  • denied
  • unsupported
  • conflict
  • unavailable
  • invalid-input
  • cancelled
  • outcome-unknown
  • internal

enum entry-kind

Anything that is neither a file nor a directory, such as a link, is reported as other rather than flattened into one of the two.

Enum Cases
  • file
  • directory
  • other

type revision

string

An opaque version token, at most 4096 UTF-8 bytes.

variant locator

How one resource is named: a path within the connection root.

Variant Cases
  • path: string

record capabilities

Optional operations. False capabilities must return unsupported. Conditional-write promises atomic create-only and revision comparisons. Virtual-directories says a directory is only ever a prefix of something stored, as in a flat object store: the host then never offers to create an empty one, warns that removing the last child removes the folder, and does not call a vanished folder an error. Such a provider may still accept mkdir by writing a marker, and must answer unsupported when asked to rename a directory.

Record Fields
  • write: bool
  • mkdir: bool
  • rename: bool
  • remove: bool
  • conditional-write: bool
  • watch: bool
  • virtual-directories: bool

record file-info

Byte length and an opaque revision, each if known.

Record Fields

record entry

One child name, without slashes, dot segments, or control characters.

Record Fields

record list-page

At most the requested number of entries. A cursor (maximum 4096 bytes) identifies another page; absence means enumeration is complete.

Record Fields
  • entries: list<entry>
  • cursor: option<string>

variant write-condition

Atomic preconditions: absent file, exact opaque revision, or unconditional replacement. Providers must never simulate comparisons non-atomically.

Variant Cases
  • create-only
  • if-match: revision
  • overwrite

enum change-kind

Changes since a previous polling cursor.

Enum Cases
  • created
  • modified
  • removed

record change

A changed resource path relative to the connection root.

Record Fields

record change-page

At most 256 changes and a cursor of at most 4096 UTF-8 bytes.

Record Fields
  • changes: list<change>
  • cursor: option<string>

resource reader

One transfer being read. The handle survives between host calls, so a file of any size is read as a series of separately bounded calls. Dropping it releases whatever the provider held open.

resource writer

One transfer being written. Dropping the handle before it finishes abandons the transfer, and the provider must leave no partial file.

Functions

[method]reader.pull: func

Reads onward from the last position, at most limit bytes, with limit between 1 and 1,048,576. An empty result means end of file.

Params
  • self: borrow<reader>
  • limit: u32
Return values

[method]reader.revision: func

The revision this transfer is reading, once the provider knows it. A provider that sees the revision change mid-transfer must fail the next pull with conflict rather than mix two versions.

Params
Return values

[method]writer.push: func

Appends at most 1,048,576 bytes. Oversized pushes are rejected, never truncated.

Params
  • self: borrow<writer>
  • data: list<u8>
Return values

[method]writer.finish: func

Commits the transfer and evaluates the write condition now, against the state the caller last saw. A none result means the commit needs another call: keep calling until it answers some, and treat an interruption in between as outcome-unknown.

Params
Return values

open: func

Opens exactly one host-owned connection per component instance. The host passes only this connection’s configuration and in-memory credentials.

Params
  • provider-id: string
  • config: list<(string, setting)>
Return values

close: func

Best-effort cleanup before disposal. The host may dispose immediately after a trap, cancellation, permission change, or process shutdown.

stat: func

Reads metadata without changing the resource.

Params
Return values

list: func

Enumerates 1-256 direct children per request, without recursive traversal.

Params
  • target: locator
  • cursor: option<string>
  • limit: u32
Return values

open-read: func

Begins reading at a byte offset. Streaming, rather than one capped read, is what lets a provider serve a file larger than a single call allows.

Params
Return values

open-write: func

Begins replacing one complete file if the write capability is present. The size hint, when the caller knows it, lets a provider choose between a single request and a multipart upload before the first byte.

Params
Return values

mkdir: func

Creates one directory if the mkdir capability is present.

Params
Return values

rename: func

Renames within this connection if the rename capability is present.

Params
  • target: locator
  • destination: string
Return values

remove: func

Removes one file or empty directory if the remove capability is present.

Params
Return values

poll: func

Polls for a bounded change page if the watch capability is present. No background callback or persistent subscription is installed by the host.

Params
  • cursor: option<string>
Return values