Development and device integration
Keragi is not limited to the bundled clients: the server can load custom WASM resources, and devices can join the messaging system through a gateway or as a client participant. This page covers the interface model, a simple example and device integration patterns.
1. Two extension paths
- Custom WASM resources: run inside the wasmx host, register HTTP / SSE / WebSocket routes, and use host-provided database, clock, object storage and other capabilities. Suitable for device gateways, protocol adapters, automation and internal tools.
- Device integration: devices do not run the wasmx host themselves (the host currently supports Linux x86_64 only). Devices connect to a custom gateway resource over HTTP, MQTT, serial or another protocol, or join conversations as a client participant.
2. Custom WASM resources
2.1 Runtime model
- A resource is compiled as a
wasm32-unknown-unknowncdylib, loaded by the host fromwasmx.jsonand mounted under itsprefix. - Resources do not perform file, network or thread I/O directly; database, clock, object storage and similar operations go through host functions.
- Normal HTTP handlers are supported, along with SSE, WebSocket and upload data planes.
- A resource can use its own SQLite database and integrate with
userxauthentication and scopes as needed.
2.2 Simple example: hello + echo
The minimal resource below exposes GET /demo/hello and POST /demo/echo.
Cargo.toml:
[package]
name = "hello-resource"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[features]
default = ["wasm"]
wasm = ["wasm-core/wasm"]
[dependencies]
wasm-core = { version = "0.1", default-features = false }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
src/lib.rs:
use serde::{Deserialize, Serialize};
use wasm_core::{get, post, wasm_handler, wasm_main, Json, Router};
#[wasm_main]
fn router() -> Router {
Router::new()
.route("/hello", get(hello))
.route("/echo", post(echo))
}
#[wasm_handler]
async fn hello() -> String {
"hello from hello-resource".to_string()
}
#[derive(Deserialize)]
struct EchoRequest {
message: String,
}
#[derive(Serialize)]
struct EchoResponse {
message: String,
}
#[wasm_handler]
async fn echo(Json(req): Json<EchoRequest>) -> EchoResponse {
EchoResponse { message: req.message }
}
Build:
cargo build --release --target wasm32-unknown-unknown \
--no-default-features --features wasm
The output is target/wasm32-unknown-unknown/release/hello_resource.wasm.
2.3 Packaging and installation
Resource directory:
hello-resource/
├── package.json
├── wasmx.resource.json
└── wasm/hello.wasm
package.json:
{
"name": "@example/hello-resource",
"version": "0.1.0",
"files": ["wasm", "wasmx.resource.json"]
}
wasmx.resource.json:
{
"resources": [
{
"name": "hello",
"file": "hello.wasm",
"config": { "prefix": "/demo", "allow_http": true }
}
]
}
Install and start:
cp target/wasm32-unknown-unknown/release/hello_resource.wasm \
hello-resource/wasm/hello.wasm
wasmx add ./hello-resource
wasmx stop
wasmx start
curl http://127.0.0.1:3001/demo/hello
curl -X POST http://127.0.0.1:3001/demo/echo \
-H 'content-type: application/json' \
-d '{"message":"hi"}'
The example uses the current Rust SDK interface. How the official SDK, macros, templates and examples will be distributed will be announced with the developer edition; if the interface changes, the SDK documentation for that version governs.
2.4 Data and authentication
- Database: use the SDK’s
db()with the host-injected database connection; schema SQL is declared with the resource and applied by the host at load time. - Authentication: resources that need a signed-in user should verify tokens issued by
userxand enforce scopes. - Secrets: keep sensitive configuration in the host or resource-specific
.env, never in code or images. - Compatibility: resource and host versions must match; re-verify resources after upgrading the host.
3. Device integration
3.1 Three integration modes
| Mode | Data path | Can it read end-to-end encrypted messages? | Typical use |
|---|---|---|---|
| Device as a client participant | Device holds its own identity and keys and joins specific conversations/channels | Yes, but only conversations it is a member of | Devices with secure storage and enough compute |
| WASM gateway resource | Device ↔ gateway resource ↔ messaging system | No for end-to-end encrypted messages; only plaintext/bot channels or client-side bridging | Sensors, actuators, HTTP/MQTT devices |
| Local edge bridge | Device ↔ local bridge (client) ↔ conversations | Yes; the bridge machine becomes a trusted endpoint | Home, industrial, serial/GPIO devices |
Encryption boundary: the server only holds ciphertext, so a server-side WASM gateway cannot decrypt end-to-end encrypted messages. Devices that need to read encrypted messages must join as client participants, or be controlled by a local bridge that decrypts on the client side.
3.2 Typical data flows
- Sensor telemetry: device
POST /device/{id}/telemetry→ gateway writes a message/channel event → clients, bots and alerting consume it. - Command delivery: client sends a command message → local bridge (client) decrypts → MQTT / serial → relay or actuator.
- Gateway subscription: gateway subscribes to a plaintext/bot channel or receives a webhook → calls the device’s HTTP/MQTT endpoint.
3.3 Example endpoints
These are endpoints a gateway resource can implement; the device-side protocol is up to you:
| Method | Path | Purpose |
|---|---|---|
POST | /device/{id}/telemetry | Report sensor data, e.g. {"temperature":23.5,"ts":...} |
GET | /device/{id}/commands | SSE/WebSocket long connection for commands |
POST | /device/{id}/ack | Acknowledge command execution |
POST | /device/{id}/relay | Control a relay/actuator, e.g. {"channel":1,"on":true} |
GET | /device/{id}/state | Query device state |
3.4 Authentication and security
- Give every device its own ID and credentials; never reuse an administrator account.
- Authenticate every control endpoint and authorize per device/user/operation.
- Apply rate limits, timeouts and idempotency keys to avoid duplicate commands and storms.
- Store device credentials in secure storage and support rotation; never hard-code them in firmware or log them.
- Use TLS or a controlled network between gateway and devices; never expose management endpoints directly to the internet.
- Log command dispatch, execution and failures for auditing and troubleshooting.
3.5 Actuators and physical safety
Important: Relays, motors, valves and other actuators involve personal and property safety. Design fail-safe behavior, emergency stop, timeout reset, authorization and manual override, and test before connecting real loads. The examples here describe software integration only and are not an industrial safety certification or guarantee.
3.6 ESP32 and similar devices
- The wasmx host currently supports Linux x86_64 only and does not run on ESP32 or other MCUs.
- ESP32-class devices can connect to a gateway resource over HTTP/MQTT, or act as a lightweight client participant where the resource permits.
- The device-side protocol, firmware and secure storage are the integrator’s responsibility; the server only provides messaging and resource capabilities.
4. Related pages
- WASM resource packs: install, combine and upgrade existing resources.
- Data storage: server/client data boundaries, keys and deletion risks.
- Data and security: security model, hardening and disclaimer.
- Licensing and pricing: licensing notices for custom resources and commercial use.