A lightweight, reactive state management library for Svelte 5 with middleware support.
Inspired by the simplicity of Zustand and the power of Svelte’s reactive runes, this library provides a single‑file API to create global or scoped state stores—complete with middleware (like logging) and full TypeScript support.
$state
rune for fine‑grained reactivity.consoleLogMiddleware
, validation with validationMiddleware
, etc.).subscribe
method under the hood so you can directly use the store in your Svelte components (no extra wrappers required).Install via npm (or your preferred package manager):
npm install astand
# or
pnpm add astand
# or
yarn add astand
Use the createStore
function to create a store with an initial state and optional middleware. For example, create a counter store that logs every state update:
// src/stores/counterStore.svelte.ts
import { consoleLogMiddleware, createStore, type Store } from '$lib/store.svelte.js';
interface CounterState {
count: number;
}
export interface CounterStore extends Store<CounterState> {
increment: () => void;
decrement: () => void;
}
const initialState: CounterState = { count: 0 };
const options = {};
const baseCounterStore = createStore<CounterState>(initialState, options);
export const counterStore: CounterStore = {
...baseCounterStore,
increment: () => {
baseCounterStore.setState((prev) => ({ count: prev.count + 1 }));
},
decrement: () => {
baseCounterStore.setState((prev) => ({ count: prev.count - 1 }));
}
};
Since the store implements Svelte’s store contract (with a subscribe
method), you can import and use it directly in your Svelte components:
<!-- src/components/Counter.svelte -->
<script lang="ts">
import { counterStore } from '../stores/counterStore.svelte';
</script>
<main>
<h1>Counter: {$counterStore.count}</h1>
<button on:click={() => counterStore.increment()}>âž• Increment</button>
<button on:click={() => counterStore.decrement()}>âž– Decrement</button>
</main>
Svelte will auto‑subscribe to your store and update the component whenever state changes.
This is a work in progress. For the moment, you can log the state everytime there is a change in the store by using the consoleLogMiddleware
.
// src/stores/counterStore.svelte.ts
import { consoleLogMiddleware, createStore, type Store } from '$lib/store.svelte.js';
interface CounterState {
count: number;
}
export interface CounterStore extends Store<CounterState> {
increment: () => void;
decrement: () => void;
}
const initialState: CounterState = { count: 0 };
const options = { middleware: [consoleLogMiddleware] }; // 🚀 Add the middleware here!
const baseCounterStore = createStore<CounterState>(initialState, options);
export const counterStore: CounterStore = {
...baseCounterStore,
increment: () => {
baseCounterStore.setState((prev) => ({ count: prev.count + 1 }));
},
decrement: () => {
baseCounterStore.setState((prev) => ({ count: prev.count - 1 }));
}
};
The main exports from the library are:
subscribe
method that yields an object with each key’s current state.combinedStore.counter.increment()
.type ValidationCondition<T> = {
predicate: (state: T) => boolean;
message: string;
level?: 'log' | 'warn' | 'error';
};
const options = {
persist: { key: 'counterStore', storage: 'local' }
};
const options = {
middleware: [
consoleLogMiddleware,
validationMiddleware([
{
predicate: (s: { count: number }) => s.count >= 0,
message: 'Count must be non-negative',
level: 'error'
}
])
],
persist: { key: 'testMiddlewareStore', storage: 'local' }
};
const store = createStore({ count: 0 }, options);