Files
craft-libs/crates/web-api/README.md
T
FredAppsandCursor f1ae1ecacb Merge main into web-host
Keep both craft-web-api and craft-web-host in the workspace list, the
README and the lockfile. Point the host README at the command API that
landed in #413, and the command API README at these host messages.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-05 10:29:52 +01:00

2.9 KiB

craft-web-api

The page command API for every Craft web build: one window.<app> shape over the app's JSON control channel.

The JS API

PageApi::install puts this on window.<app> ("vectorcraft" → window.vectorcraft), without replacing an existing window.<app>: missing functions are added, an app that already has its own keeps them. Each function returns a Promise that resolves with the method's result or rejects with an Error carrying error. Every call has a timeout (30 s by default, PageApi::with_timeout); when the app does not answer in time, the error says so.

Which functions are installed follows the app's Methods table: only the functions whose control method the table provides are installed; request is always there.

Function Call Table entry Default method
request request(method, params) — — (as given)
execute execute(command, params) execute engine.execute {command, params}
commands commands() commands engine.commands {}
docInspect docInspect(params) doc_inspect document.inspect
uiInspect uiInspect(params) ui_inspect ui.inspect
screenshot screenshot(params) screenshot ui.screenshot (with data: true)

Methods::default() is the desktop control-server method names; an app whose control channel names a method differently, or lacks one, says so in its table (Methods::NONE is the empty table).

How an app wires it

The app hands the crate its control channel as a Request; the crate never knows the app's internals. Using VectorCraft's channel (the same one the desktop control server uses) as the example:

use std::rc::Rc;

use craft_web_api::methods::Methods;
use craft_web_api::page::{PageApi, Request};

// Send a ControlRequest to the app and await its reply object ({ok, result} / {ok: false, error}).
let request: Request = Rc::new(move |method: String, params: serde_json::Value| {
    let (req, rx) = ControlRequest::new(method, params);
    control_tx.send(req);
    Box::pin(poll_reply(rx)) // resolves when the app answers the request
});
let page = Rc::new(PageApi::new("vectorcraft", Methods::default(), request));
page.install()?; // window.vectorcraft

Beside the host messages

Opening a document, handing a saved or exported file to the host, the document name and the dirty flag stay with the host messages in craft-web-host (<app>:open, <app>:save, <app>:dirty, …) and the app's own control methods. A page reaches any control method through request(method, params).

Tests

src/methods.rs carries the native unit tests (the default and empty tables). tests/page.rs runs under wasm-bindgen-test in Node with a canned control channel: install and keeping an app's own functions, the table deciding which functions exist, the method and params each function sends, error replies as rejections, and the timeout.