~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/atlibs

0
0
main
126 lines · 5.7 KB Raw History

Transports

Some modules need more than XRPC: a shell on a VM over iroh, or a WebRTC datachannel from a page. A transport serves com.fedfork.exec.<name>.connect calls for a host. Hosts take transports as plugins; the core never imports one, and a host without it refuses its calls.

transportNSID, URLshostsrepo
irohcom.fedfork.exec.iroh.connect, iroh:Node, Rust (cargo feature iroh, on by default)atlibs-iroh
WebRTCcom.fedfork.exec.webrtc.connect, webrtc:browseratlibs-webrtc

Fetch a URL

A transport can also carry plain HTTP: com.fedfork.exec.http.fetch sends a URL of its scheme to it (other URL schemes), so a module talks to a service in a guest VM, the socialweb.computer guest agent's MCP server (Streamable HTTP on a unix socket), as it would to any HTTP server. The URL is self-contained; its ref is base64url JSON of what the transport needs, nothing secret:

  • webrtc:///<ref>/<tag>/<path>: ref { "receipt": { "uri", "cid" }, "bidder"? }, tag the guest's datachannel tag (shell), e.g. webrtc:///<ref>/shell/mcp
  • iroh:///<ref>/<socket>/<path>: ref { "ticket", "hostKeys": [...] }, socket shell (/run/socialweb-guest-agent/shell.sock) or a percent-encoded absolute unix path

The module's http lists webrtc://* or iroh://*, and so must the host's allowlist.

Require a transport

A module that needs one lists the NSID in calls and declares it as a required hook, so a host without the transport refuses it at load rather than mid-run:

examples/rust/echo/module.json

	"hooks": [
		{ "nsid": "com.fedfork.exec.iroh.connect", "required": true, "entries": ["session", "connect"], "reason": "session and connect dial the guest over iroh: a host built without iroh refuses them at load" }
	]

The Node CLI loads no transport unless asked, so echo's iroh entries are refused:

node javascript/src/server/cli.mjs run target/wasm32-unknown-unknown/release/echo.wasm examples/rust/echo/module.json session '{"ticket":"x"}' | jq -r .error
Echo needs hook com.fedfork.exec.iroh.connect (…): this host was built without iroh

Plug one in

JS: a transport is a map of NSID to call, passed as hostCall's calls, and its fetchers(), a map of scheme to fetch, { "webrtc:": async ({ method, url, headers, body, signal }) => ({ status, headers, body }) }, spread into runModule's (or runCompose's) fetchers. The Node CLI loads modules named in ATLIBS_TRANSPORTS, each exporting transport and/or fetchers({ env, stateDir }) (atlibs-iroh's is js/index.js):

ATLIBS_TRANSPORTS=../atlibs-iroh/js/index.js node javascript/src/server/cli.mjs run target/wasm32-unknown-unknown/release/echo.wasm examples/rust/echo/module.json session '{"ticket":"<an iroh ticket>"}'

Rust: a Transport says which NSIDs it provides and the Call that serves them; the CLI registers the ones it was built with. Its Call may also fetch URL schemes of its own, gathered by transport::fetchers() into the http allowlist (ATLIBS_HTTP names them, {"iroh://*": {}}):

rust/host/src/transport.rs

/// A transport: the NSIDs it provides (request and subscribe) and the call that serves them.
#[derive(Clone)]
pub struct Transport {
    pub provides: &'static [&'static str],
    pub call: Arc<dyn Call>,
}

rust/host/src/run.rs

    /// The URL schemes (no colon: "iroh") whose HTTP_NSID requests this call serves with fetch(): a
    /// transport's (transport::fetchers). None by default.
    fn schemes(&self) -> &'static [&'static str] {
        &[]
    }
    /// One HTTP_NSID request to a URL of one of schemes() (JS: a fetchers entry), as host::Fetch::fetch.
    fn fetch(&self, _method: &str, url: &str, _headers: Vec<(String, String)>, _body: Option<Vec<u8>>) -> BoxFut<'_, Result<crate::host::Response, String>> {

rust/cli/src/main.rs

pub fn transports(state_dir: &Path) -> Transports {
    #[allow(unused_mut)]
    let mut transports: Transports = vec![];
    #[cfg(feature = "iroh")]
    transports.push(atlibs_iroh::transport(env("ATLIBS_IROH_KEY").map(PathBuf::from).unwrap_or_else(|| state_dir.join("iroh_ed25519"))));
    transports
}

The CLI's iroh feature takes atlibs-iroh by git; rust/Cargo.toml patches that crate's atlibs-host to this checkout, so one atlibs-host is built. cargo loopback builds atlibs without iroh, for checking that refusal.

iroh

atlibs-iroh dials an iroh ticket with dumbpipe (brew install dumbpipe): an ssh command on the guest, or a raw ALPN exchange. With subscribe: true it is a session: output arrives as messages, and send writes stdin. The host's ssh key never enters wasm (ATLIBS_IROH_KEY, else <state>/iroh_ed25519). Its tests run both CLIs from an atlibs checkout next to it:

cd ../atlibs-iroh && node --test js/*.test.mjs examples/*.test.mjs tests/*.test.mjs   # tests/loopback: real dumbpipe into a throwaway sshd

WebRTC

atlibs-webrtc gives a page WebrtcHost (js/index.js): it finds the guest's offer, answers, opens a datachannel and can run ssh over it. Signalling goes through the module (sealed with age); connectivity is STUN only. Its loopback test runs headless Chrome against its webrtc-peer into a throwaway sshd:

cd ../atlibs-webrtc && cargo build --release && node --test js/*.test.mjs tests/*.test.mjs

STUN only. There is no TURN relay: two peers behind symmetric NATs will not connect.

Previous: Policies | Next: Examples