Bastion.Cmd
lib/cmd.march — Bastion.Cmd: typed commands from island update functions.
Islands (WASM modules compiled from March) follow the Elm Architecture pattern:
update(state, msg) → (new_state, Cmd(Msg))A Cmd represents a side-effect — an HTTP request, a timer, a navigation event, a channel message, or a direct JS call — that the runtime (wasm-bridge.js / the Bastion client runtime) executes on behalf of the island after each update.
── Usage in an island ──────────────────────────────────────────────────────────
import Bastion.Cmd as Cmd
type Msg =
| Increment
| LoadUser(Int)
| GotUser(String)
fn update(state, msg) do
match msg do
Increment ->
({ count: state.count + 1 }, Cmd.none())
LoadUser(id) ->
(state, Cmd.http_get("/api/users/" ++ String.from_int(id), fn resp ->
GotUser(resp.body)
end))
GotUser(json) ->
({ state | user = json }, Cmd.none())
end
end── JS Runtime Support ──────────────────────────────────────────────────────────
The Bastion JS runtime (wasm-bridge.js + march-islands.js) interprets Cmd values returned by island update functions. The WASM module must export march_island_update_cmd() alongside march_island_update() for the runtime to receive both the new state AND the command.
Commands are serialised to a JSON envelope by the March compiler's WASM target; the JS runtime dispatches based on the "tag" field.
JSON envelope schema: { "tag": "None" } { "tag": "Batch", "cmds": [...] } { "tag": "HttpGet", "url": "...", "ref": "<callback_id>" } { "tag": "HttpPost", "url": "...", "body": "...", "ref": "<callback_id>" } { "tag": "After", "ms": 500, "msg": <msg_json> } { "tag": "Every", "ms": 1000, "msg": <msg_json> } { "tag": "Focus", "id": "input-field" } { "tag": "Blur", "id": "input-field" } { "tag": "PushUrl", "path": "/new-page" } { "tag": "ReplaceUrl", "path": "/same-page" } { "tag": "StoreLocal", "key": "prefs", "value": "..." } { "tag": "LoadLocal", "key": "prefs", "ref": "<callback_id>" } { "tag": "RemoveLocal", "key": "prefs" } { "tag": "ChannelPush", "event": "msg", "payload": "..." }
Types
Functions
Deliver msg after delay_ms milliseconds (one-shot).
Cmd.after(500, HideNotification)Execute a list of commands in parallel. All commands in the batch are dispatched; their result messages are delivered back to the island.
Cmd.batch([http_cmd, timer_cmd])Blur (unfocus) the DOM element with the given id.
Cmd.blur("dropdown-menu")Push a message to the island's wired channel topic (Client-mode islands only). The event and payload_json are forwarded to the server-side channel handler.
Cmd.channel_push("new_message", "{\"text\":\"hello\"}")Deliver msg every interval_ms milliseconds (repeating). The timer fires until the island is destroyed.
Cmd.every(5000, RefreshData)Focus the DOM element with the given id.
Cmd.focus("search-input")Perform an HTTP GET request. When the response arrives, handler is called with the response body string and the returned message is dispatched.
Cmd.http_get("/api/users", fn body -> GotUsers(body) end)Perform an HTTP POST request with a body string.
Cmd.http_post("/api/items", "{\"name\":\"Alice\"}", fn body -> Created(body) end)Read a value from localStorage. handler receives Some(value) if present or None if the key is absent; the returned message is dispatched.
Cmd.load_local("theme", fn opt -> LoadedTheme(Option.unwrap_or(opt, "light")) end)Push a new URL onto the browser history stack. Does not trigger a page reload.
Cmd.push_url("/users/42")Remove a key from localStorage.
Cmd.remove_local("session_draft")Replace the current URL in the browser history stack (no new entry).
Cmd.replace_url("/search?q=alice")