Svelte x Node
A Svelte frontend talking to a Node/Express backend that records audit events via sdk-node 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-node-be
Stack
| Layer | What it is |
|---|---|
| Frontend | Svelte 4, Vite, @everscribe/components-element |
| Backend | Node 20+, Express, tsx, @everscribe/sdk-node |
| 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-node-be/single-tenant # or .../multi-tenant
cp .env.example .env # EVERSCRIBE_PROJECT_ID + EVERSCRIBE_API_KEY
npm install
cd frontend && npm install && npm run build && cd ..
npm start
Server on :3000 serves the Svelte bundle and the API.
Backend integration
Identical to the React + Node backend — the SDK doesn't know which frontend is on the other side:
import { create } from "@everscribe/sdk-node";
import * as minter from "@everscribe/sdk-node/minter";
const es = create(process.env.EVERSCRIBE_PROJECT_ID!, process.env.EVERSCRIBE_API_KEY!);
const rec = es.newRecorder({ flushInterval: 2_000 });
const m = new minter.Client(process.env.EVERSCRIBE_PROJECT_ID!, process.env.EVERSCRIBE_API_KEY!);
Recording from a route handler:
await rec.record({
action: "secret.reveal",
actor: actorFor(req),
target: { type: "secret", id: req.params.id },
result: { status: "ok" },
});
See React + Node → Backend integration for the full mint endpoint.
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", {
credentials: "include",
headers: { "X-Demo-Actor": currentUser.id },
});
return (await res.json()).token;
};
}
</script>
<audit-trail bind:this={el} />
Real apps swap X-Demo-Actor for whatever auth your backend expects.
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 Express server and the Svelte build share one port.
express.static('frontend/dist')is everything. - Custom elements work without a wrapper. Svelte's attribute / event-listener syntax flows through cleanly.
- Backend code is identical to the React variant. Frontend choice is local.