Skip to content

Dependencies

A dependency is a WebAssembly module the host mounts beside the handlers, from a registry the operator curates.

dependencies: {
db: {
module: "sqlite3-wasi",
version: "3.50",
sha256: "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
persistent: true,
init: "db/schema.sql",
},
},
import type { AddExpenseHandler } from "../.embabel/realm.d.ts";
export const addExpense: AddExpenseHandler = async (input, ctx) => {
await ctx.deps.db.exec("INSERT INTO expenses (amount, note) VALUES (?, ?)", [input.amount, input.note]);
const rows = await ctx.deps.db.exec("SELECT sum(amount) AS total FROM expenses");
return { total: rows[0]?.total ?? 0 };
};
  • The key becomes ctx.deps.<key>: a JavaScript identifier, and not log or gateway. ctx.deps exists only when the realm declares a dependency.
  • module is a registry id ([a-z0-9][a-z0-9-]*), version an exact version such as 3.50 (one to three dot-separated numbers), and sha256 the digest of the module’s bytes, 64 lowercase hex characters. The host refuses a module the operator has not allowed, and one whose bytes do not hash to sha256. Either refusal takes every handler in the realm dark, including the ones that never touch the dependency. The reference host allows sqlite3-wasi and h3-wasi, at most eight dependencies, and modules up to 32 MiB.
  • SQLite has one method, exec(sql, params), which resolves to rows as plain objects. Bind values through params (strings, numbers or null). A sqlite3-wasi dependency may not declare methods.
  • Any other module may declare the methods it calls, each with args and a returns type from i32, i64, f32 and f64, and the generated types give ctx.deps.<key> exactly those methods. An i64 travels as a decimal string, since values such as an H3 cell id do not fit a JavaScript number. A module with no declared methods is typed unknown. The operator’s allowlist decides what a module may really do; a declared method the operator has not allowed refuses at call time.
  • Without persistent, state lives for one dispatch and starts empty each time.
  • With persistent: true, the host keeps one database for each world, realm and dependency. It restores the database at the start of a dispatch and saves it only when the dispatch succeeds and the output passes validation; a failed or refused dispatch leaves the stored rows as they were.
  • init is a script, relative to the realm with no leading / and no .., run against empty state: once per dispatch for ephemeral state, or once when a persistent database is created. Synth refuses a missing file and copies it into the output. The host copies it from the admitted capture (at most 1 MiB), so editing the file later changes nothing for the admitted version.
  • The host records the module, version, digest and init script’s hash beside a persistent database. Change any of them and the host reports a mismatch and refuses to reuse the database. It neither wipes nor migrates it, and there is no migration step, so settle the schema before the first install that persists, and ship a changed schema under a new dependency key.
  • layers takes name@version references (a registry id and one to three dot-separated numbers), which synth checks and writes, sorted, to dependencies/manifest.json. The reference host refuses a realm that declares them, so leave them out. --profile reference-wasm and --profile reference-docker refuse them too.