Svelte x Rust

A Svelte frontend talking to a Rust/axum backend that records audit events via sdk-rust and serves the Svelte bundle on the same port. Comes in single-tenant and multi-tenant variants.

Source: https://github.com/everscribe/examples/tree/main/svelte-fe-with-rust-be

Stack

Layer What it is
Frontend Svelte 5, Vite, @everscribe/components-element
Backend Rust (axum + tokio), everscribe
Domain In-memory secrets vault
Audit panel <audit-trail> custom element

Run it

git clone https://github.com/everscribe/examples
cd examples/svelte-fe-with-rust-be/single-tenant   # or .../multi-tenant

cp .env.example .env   # EVERSCRIBE_PROJECT_ID + EVERSCRIBE_API_KEY
(cd frontend && npm install && npm run build)

cargo run

Server on :9000 serves the Svelte bundle and the API.

Backend integration

Identical to the React + Rust backend. The SDK doesn't know which frontend is on the other side:

let es = everscribe::new(project_id, api_key)?;
let rec = es.new_recorder(Default::default());
let minter = es.new_minter(Default::default());

let api = Router::new()
    /* routes */
    .layer(EverscribeLayer::new(rec, resolve_actor))
    .with_state(state);

Handlers enrich CurrentEvent; the layer records on response finish. See React + Rust → Backend integration for the full reveal + mint handlers.

Frontend integration

Custom elements are first-class in Svelte:

<script>
    import "@everscribe/components-element";
    import "@everscribe/components-styles/default.css";
</script>

<audit-trail token-endpoint="/api/embed-token"
             on:audit-trail-error={(e) => console.error(e.detail.error)} />

For the multi-tenant customer view, attach the X-Demo-Actor header via the JS-only onTokenExpired property:

<script>
    let el;
    $: if (el) {
        el.onTokenExpired = async () => {
            const res = await fetch("/api/embed-token/customer", {
                method: "POST",
                credentials: "include",
                headers: { "X-Demo-Actor": currentUser.id },
            });
            return (await res.json()).token;
        };
    }
</script>

<audit-trail bind:this={el} />

Single-Tenant vs Multi-Tenant

Single-tenant Multi-tenant
Token endpoint One. /api/embed-token Two. /api/embed-token/customer, /api/embed-token/admin
UI One vault view Tab strip: Customer view · Admin view
Seeded data One implicit tenant Acme, Initech
Audit-panel scope Whole project Customer: tenant-scoped · Admin: unscoped

What to take away

  • The axum server and the Svelte build share one port (tower-http's ServeDir serves frontend/dist).
  • Custom elements work without a wrapper.
  • Backend code is identical to the React variant.

What next