intentx-svelte is an architectural layer for Svelte. It enforces a strict separation between:
It is not a store library.
It is a bridge between deterministic logic and Svelteβs reactive UI.
Use it when your UI starts to feel like business logic.
β
Complex async workflows
β
Intent-based architecture
β
Microfrontend communication
β
Testable business logic
β
Cross-runtime reuse (Node / SSR / workers)
Avoid it when:
β You only need $: reactive statements
β Your state is purely local UI
β You want reducer-style state
Svelte stores are excellent for reactivity.
But they do not provide:
Stores solve reactivity.
intentx solves orchestration.
UI / HTTP / Queue / Cron
β
intentx-runtime
β
Fine-grained reactivity updates UI
Core principle:
Intent is the only mutation entry point. The runtime owns behavior. UI only triggers intent.
npm install intentx-svelte
Define logic outside components:
import { createLogic } from "intentx-svelte"
export const counterLogic = createLogic({
name: "counter",
state: {
count: 0
},
computed: {
double: ({ state }) => state.count * 2
},
intents: (bus) => {
bus.on("inc", ({ setState }) => {
setState((s) => {
s.count++;
});
});
},
actions: {
inc({ emit }) {
return () => emit("inc");
},
},
})
Logic is:
// counter.ts
import { useLogic } from "intentx-svelte"
import { counterLogic } from "./counter.logic"
export const counter = useLogic(counterLogic)
<script>
import { counter } from "./counter"
</script>
<button on:click={counter.actions.inc}>
{$counter.store.count}
</button>
<p>Double: {$counter.store.double}</p>
No wrapper components.
No magic subscriptions.
UI only consumes state.
useLogic Returnsconst counter = useLogic(counterLogic)
{
runtime, // β LogicRuntime instance
store, // π merged state + computed (Svelte store)
state, // πͺ alias of store
actions, // π― logic actions
emit // π‘ emit intent
}
π₯ Important
store is readonlyEach logic instance is isolated by default.
To enable communication between runtimes, you can share an Intent Bus.
import { useLogic } from "intentx-react"
// β
Same scope β shared bus
useLogic(logic, {
scope: "dashboard",
sharedBus: true
})
// β Different scope β different bus
useLogic(logic, {
scope: "settings",
sharedBus: true
})
How it works
When sharedBus: true is enabled:
A singleton bus is created per scope
Same scope β same bus instance
Different scope β different bus
No global leakage
If no scope is provided:
useLogic(logic, {
sharedBus: true
})
β uses a default global scope bus.
import { createIntentBus } from "intentx-svelte"
const bus = createIntentBus()
useLogic(logicA, { bus })
useLogic(logicB, { bus })
Behavior
| Mode | Isolation | Scope-aware | Cross-scope | Recommended |
|---|---|---|---|---|
| Default (no options) | β Full | β | β | Small/local logic |
sharedBus: true |
β Per scope | β | β | Modular apps |
Custom bus |
β Manual | β | β | Advanced architecture |
β
Use sharedBus for modular communication.
β
Use custom bus for orchestration layer.
π« Avoid global single bus without scope in large apps.
Provide logic via Svelte context:
import { setLogicContext, useLogicContext } from "intentx-svelte"
import { counterLogic } from "./counter.logic"
Provider:
<script>
setLogicContext("counter", counterLogic)
</script>
<slot />
Consume:
const counter = useLogicContext("counter")
Works with:
No Svelte required:
const runtime = counterLogic.create()
runtime.actions.inc()
expect(runtime.state.count).toBe(1)
No DOM.
No component mounting.
Pure deterministic logic.
That is the real split.
This is not about βbetterβ. Itβs about solving different layers of the architecture.
| Problem / Responsibility | Svelte Only | intentx-svelte |
|---|---|---|
| Local UI state | β Perfect | β Overkill |
| Simple derived values | β
$: |
β Unnecessary |
| Complex async workflows | β οΈ Manual | β Structured |
| Cross-component orchestration | β οΈ Implicit | β Explicit |
| Cross-runtime reuse (Node/SSR) | β | β |
| Deterministic snapshotting | β | β |
| Intent-based communication | β | β |
| Microfrontend signaling | β | β |
Svelte handles reactivity.
intentx handles orchestration.
Rendering is reactive.
Business logic should be deterministic.
intentx-svelte ensures they never mix.
MIT