Docs

API

Every function and type of berm-lang a service calls, with its signature, grouped by what it reaches, and the page that holds its rules.

Every item below is in berm_lang, at the tag crab new pins. Each function past the arguments is a syscall to the host; the capability's page holds its rules and limits.

A deployed image keeps running across host upgrades. A rebuild is what brings it a new berm_lang, and a host refuses an image that uses a host call it doesn't serve (E0020).

Results and errors

pub type Result<T, E = Error> = core::result::Result<T, E>;
pub struct Error { pub message: String }
pub enum CallError { Failed(String), Refused(String) }

pub fn deny(message: &str) -> Error;
  • A tool returns Result<T>; Err(Error) fails it, and the caller reads message.
  • Error converts from CallError, String and &str, so ? fails the tool with a syscall's message.
  • CallError::Refused means nothing ran; CallError::Failed means it ran and failed. CallError::message() and CallError::refused() read it.
  • deny(message) makes an Error that fails the call as refusing its caller; the host counts it as denied.

Callers and users

pub fn caller() -> Result<Option<Caller>, CallError>;
pub fn user() -> Result<Option<User>, CallError>;
pub fn client() -> Result<Option<String>, CallError>;
pub fn client_ip() -> Result<Option<core::net::IpAddr>, CallError>;
pub fn vouch(subject: &str) -> Result<(), CallError>;

pub enum Caller { Outside(String), Service(String) }
pub struct User { pub issuer: String, pub subject: String }

Rules: Callers and users.

State and data

pub fn get(key: &str) -> Result<Option<Vec<u8>>, CallError>;
pub fn set(key: &str, value: &[u8]) -> Result<(), CallError>;
pub fn get_json<T: for<'de> Deserialize<'de>>(key: &str) -> Result<Option<T>, CallError>;
pub fn set_json<T: Serialize>(key: &str, value: &T) -> Result<(), CallError>;

pub fn sql(statement: &str, params: &str) -> Result<String, CallError>;
pub fn rows<T: DeserializeOwned>(statement: &str, params: &impl Serialize) -> Result<Vec<T>, CallError>;
  • rows binds a tuple to the statement's ?s in order and answers each row as T, a tuple of its columns in order. sql takes the parameters as a JSON array and answers JSON.

Rules: Data.

Vars

pub fn var(name: &str) -> Result<String, CallError>;

Rules: Vars.

HTTP

pub mod http {
    pub struct Client<'a> { pub name: &'a str, pub headers: &'a [(&'a str, &'a str)] }
    // Client::request(&self, method: &str, url: &str, body: &[u8]) -> berm_lang::Result<Response>
    // Client::json<T: DeserializeOwned>(&self, method: &str, url: &str, body: &[u8]) -> berm_lang::Result<T>
    pub fn fetch(method: &str, url: &str, headers: &[(&str, &str)], body: &[u8]) -> Result<Response, CallError>;
    pub fn proxy(method: &str, url: &str, headers: &[(&str, &str)], body: &[u8]) -> Result<Response, CallError>;
    pub fn fetch_all(requests: &[Request<'_>]) -> Result<Vec<Result<Response, CallError>>, CallError>;
    pub fn proxy_all(requests: &[Request<'_>]) -> Result<Vec<Result<Response, CallError>>, CallError>;
    pub fn form(fields: &[(&str, &str)]) -> String;
    pub fn encode(text: &str) -> String;

    pub struct Request<'a> {
        pub method: &'a str,
        pub url: &'a str,
        pub headers: &'a [(&'a str, &'a str)],
        pub body: &'a [u8],
        /// Milliseconds to wait for an answer; `None` for the call's deadline.
        pub timeout: Option<u64>,
        /// The most bytes of the body taken; `None` for all of it.
        pub limit: Option<usize>,
    }
    pub struct Response { pub status: u16, pub headers: Vec<(String, String)>, pub body: Vec<u8> }
    // Response::is_success(&self) -> bool
    // Response::header(&self, name: &str) -> Option<&str>
    // Response::failure(&self, provider: &str) -> berm_lang::Error
    // Response::read<T: DeserializeOwned>(&self, provider: &str) -> berm_lang::Result<T>
    // Response::json<T: DeserializeOwned>(&self) -> serde_json::Result<T>
}
  • A timeout or a cap on the body is given per request, through fetch_all.
  • form encodes fields as application/x-www-form-urlencoded; encode percent-encodes one value.

Rules: HTTP.

Other services and wakes

pub fn call(service: &str, tool: &str, args: &str) -> Result<String, CallError>;
pub fn after(delay: u64, service: &str, tool: &str, args: &str) -> Result<(), CallError>;
  • call answers the tool's result as JSON text. declare_service! generates typed calls over it; see Macros.
  • after runs the tool in delay milliseconds, as a wake. An empty service targets the current deployment.

Rules: Other services, Crons and wakes.

Logs, time and randomness

pub fn emit(topics: &[&str], data: &str) -> Result<(), CallError>;
macro_rules! emit { ($event:expr) => { … } }   // Result<usize, CallError>
pub trait Event { const NAME: &'static str; }

pub fn trace(message: &str);
pub fn now() -> u64;
pub fn random(buffer: &mut [u8]);
  • emit writes a log under topics, which a reader filters by; emit! writes an #[event] under its name. A log is kept beside its call for 30 days, whatever the call ended as, and holds at most 4 KiB, data and topics together. emit is refused in a query tool.
  • trace writes a line to the host's own output, not to the service's logs.
  • now is the host's time in Unix milliseconds. random fills buffer from a secure source.
  • Logs are for debugging a run. A service's data belongs in its database, read by others through its query tools.

Limits

pub fn limit(cpu: u64, rows: u64, memory: u64) -> Result<(), CallError>;

Rules: Budgets.

Testing

pub mod test {
    pub fn call(entry: extern "C" fn(), args: &[u8]) -> Result<Vec<u8>, String>;
    pub fn answer(service: &str, tool: &str, result: Result<&[u8], CallError>);
    pub fn respond(method: &str, url: &str, status: u16, body: &[u8]);
    pub fn var(name: &str, value: &str);
    pub fn fetched() -> Vec<Fetched>;
    pub fn emitted() -> Vec<(Vec<String>, String)>;
    pub fn traced() -> Vec<String>;
    pub fn forget();
}

Off WebAssembly only. Rules: Testing.