flaron-sdk 1.1.0

Official Rust SDK for writing Flaron edge flares - WebAssembly modules that run on the Flaron CDN edge runtime.
Documentation

flaron-sdk

The official Rust SDK for building flares - WebAssembly functions that run on the Flaron CDN edge.

A flare is a small Wasm module deployed to every Flaron edge node worldwide. The host runtime invokes your handle_request export when a request lands at the nearest edge, your code runs in a sandboxed runtime with single-digit-millisecond cold starts, and the response is shipped back to the client without ever touching your origin.

use flaron_sdk::{request, response, FlareAction};

flaron_sdk::handle_request!(my_flare);

fn my_flare() -> FlareAction {
    let body = format!("hello from {} {}", request::method(), request::url());
    response::set_status(200);
    response::set_header("content-type", "text/plain");
    response::set_body_str(&body);
    FlareAction::Respond
}

Installation

Add the SDK to your Cargo.toml:

[package]
name = "my-flare"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
flaron-sdk = "0.1"

[profile.release]
opt-level = "z"
lto = true
codegen-units = 1
panic = "abort"
strip = true

You will need the wasm32-unknown-unknown target installed:

rustup target add wasm32-unknown-unknown

Then build your flare:

cargo build --release --target wasm32-unknown-unknown

The resulting target/wasm32-unknown-unknown/release/my_flare.wasm is what you upload to Flaron.

Quick start: HTTP echo flare

Create a new library crate:

cargo new --lib my-flare
cd my-flare

Set the crate type to cdylib and add the SDK as in the Installation section above.

Replace src/lib.rs with:

use flaron_sdk::{logging, request, response, FlareAction};

flaron_sdk::handle_request!(my_flare);

fn my_flare() -> FlareAction {
    let method = request::method();
    let url = request::url();
    logging::info(&format!("{} {}", method, url));

    let body = format!(
        "method: {}\nurl: {}\nuser-agent: {}\n",
        method,
        url,
        request::header("user-agent").unwrap_or_default(),
    );

    response::set_status(200);
    response::set_header("content-type", "text/plain; charset=utf-8");
    response::set_body_str(&body);

    FlareAction::Respond
}

The handle_request! macro takes the name of your handler function and expands to the alloc and handle_request exports the host runtime requires. The macro resets the bump arena on every invocation and converts your returned [FlareAction] into the i64 the host expects.

For WebSocket flares the equivalent macro is ws_handlers!:

use flaron_sdk::{logging, ws};

flaron_sdk::ws_handlers!(on_open, on_message, on_close);

fn on_open() {
    let _ = ws::send_text(&format!("welcome {}", ws::conn_id()));
}

fn on_message() {
    let payload = ws::event_text();
    let _ = ws::send_text(&format!("echo: {}", payload));
}

fn on_close() {
    logging::info(&format!("ws close code={}", ws::close_code()));
}

Pass the three handler names in open, message, close order. The macro exports ws_open / ws_message / ws_close and resets the arena before each call.

Use handle_request! or ws_handlers! per crate, never both - they each define the alloc export the host runtime requires.

Build and deploy:

cargo build --release --target wasm32-unknown-unknown
flaronctl deploy target/wasm32-unknown-unknown/release/my_flare.wasm \
    --domain example.com --route '/*'

Curl the edge to see it run:

curl https://example.com/hello

Features

The SDK exposes the full Flaron edge runtime through ergonomic Rust modules. Every operation runs in the host's native code path - no allocator, no async runtime, no crypto crate gets pulled into your .wasm.

Request and response

  • request - read inbound method, url, individual header(name), and request body bytes.
  • response - write set_status, set_header(k, v), set_body(bytes), set_body_str(s).

Outbound HTTP - beam

Make HTTP calls from the edge to your origin or third-party APIs. Supports method, headers, body, and returns status, headers, and response body.

use flaron_sdk::beam::{self, FetchOptions};

let resp = beam::fetch(
    "https://api.example.com/users/42",
    FetchOptions::new()
        .with_header("authorization", "Bearer ...")
        .with_header("accept", "application/json"),
)?;

Edge KV stores

  • spark - per-site key/value with TTL, persisted to local disk on each edge node. Best for caching, session state, and rate-limit counters local to one edge.
  • plasma - cross-edge CRDT key/value replicated via gossip. Best for state that must be visible from any edge: PN counters, presence, leaderboards, feature flags.
use flaron_sdk::{spark, plasma};

spark::set("session:abc", b"data", 3600)?;     // expires in 1 hour
let session = spark::get("session:abc");

plasma::increment("page_views:home", 1);       // CRDT, gossiped to all edges

Secrets - secrets

Read domain-scoped secrets that have been allowlisted for this flare. Secret values are gated by the flare's allowed_secrets config - anything not on the list returns None.

let api_key = flaron_sdk::secrets::get("third-party-api-key");

For HMAC and JWT signing, prefer the crypto helpers - they reference secrets by name without ever exposing the raw bytes to Wasm.

Cryptography - crypto

Hash, HMAC, AES-GCM encrypt/decrypt, JWT signing, and CSPRNG random bytes. All operations run in the host's native crypto stack so they are constant-time and dramatically faster than a pure-Wasm crypto build.

use std::collections::HashMap;
use flaron_sdk::crypto;

let digest = crypto::hash("sha256", "hello world");
let mac = crypto::hmac("webhook-signing-key", "payload");

let mut claims = HashMap::new();
claims.insert("sub".to_string(), "user-42".to_string());
let jwt = crypto::sign_jwt("HS256", "session-key", &claims);

let entropy = crypto::random_bytes(32)?;

Encoding helpers - encoding

Zero-dep wrappers for base64, hex, and URL percent-encoding. Calling the host avoids pulling encoding crates into your Wasm binary.

ID generators - id

UUID v4, UUID v7 (time-ordered), ULID, KSUID, Nanoid, and Snowflake. All generated by the host's native crypto + clock so IDs are collision-resistant across edges with no entropy crate in your binary.

Time - time

Timestamps in any format you need: unix seconds, milliseconds, nanoseconds, RFC3339, HTTP date, ISO8601.

Logging - logging

info, warn, and error surfaced via the edge node's structured log stream - visible in the Flaron dashboard and forwarded to your log sink.

WebSockets - ws

Receive open / message / close events and send / close from the flare. The same module exposes event_type, event_data, event_text, and close_code for the inbound side.

Memory model

Each invocation starts with a fresh 256 KiB bump arena. The host writes return data into the arena via your exported alloc function. The handle_request! and ws_handlers! macros include the alloc export and reset the arena on every invocation - you never need to free anything.

This is why most SDK functions return owned String or Vec<u8> values: they are read out of the arena and copied into the linear-memory heap before the arena is reset on the next call.

If you need to define the host exports yourself (custom handle_request shape, multiple entry points, etc.) call flaron_sdk::export_alloc!() and flaron_sdk::reset_arena() directly instead of using the macros.

Examples

The examples/ directory contains seven complete flares you can build today:

Example What it shows
hello Minimal HTTP responder
spark-counter Per-edge KV with TTL
plasma-counter Cross-edge CRDT counter
secret-jwt Sign a JWT with a domain secret
websocket-echo WebSocket open / message / close
beam-fetch Outbound HTTP from the edge
edge-ops Crypto, encoding, ID, and timestamp showcase

Build them all from the workspace root:

cargo build --release --target wasm32-unknown-unknown

Each example is a workspace member - its .wasm lands in target/wasm32-unknown-unknown/release/<example_name>.wasm.

Documentation

License

MIT - see LICENSE.