Type-safe reactive primitives with one contract: get(), subscribe(), set(). Works with in-memory state, validated localStorage / IndexedDB, media queries, scroll position. Bindings for React, Vue, Solid, Svelte. SSR-safe.
pnpm add seituImport from an entry point (seitu, seitu/web, seitu/react, seitu/vue, seitu/solid, seitu/svelte, seitu/utils) or from a single feature to pull in nothing else:
import { createStore } from 'seitu/core/store'
import { createWebStorage } from 'seitu/web/web-storage'import { createComputed, createStore } from 'seitu'
const cart = createStore({ items: [{ price: 10, qty: 2 }], coupon: 0.1 })
const total = createComputed(
cart,
(c) => c.items.reduce((s, i) => s + i.price * i.qty, 0) * (1 - c.coupon)
)
total.get() // 18
cart.set((c) => ({ ...c, coupon: 0 }))
total.subscribe((t) => console.log(t)) // 20import { createDebounced, createDebouncedFn, createStore } from 'seitu'
const query = createStore('')
createDebounced(query, 300).subscribe((q) => fetch(`/search?q=${q}`))
const save = createDebouncedFn((draft: string) => api.save(draft), 500)
save('hello') // runs after 500 ms of silence
save.flush() // or nowimport { createWebStorage, createWebStorageValue } from 'seitu/web'
import * as z from 'zod'
const settings = createWebStorage({
type: 'localStorage',
schemas: {
theme: z.enum(['light', 'dark']),
sidebar: z.object({ open: z.boolean() }),
},
defaultValues: { theme: 'light', sidebar: { open: true } },
})
settings.set({ theme: 'dark' }) // partial update
settings.get() // { theme: 'dark', sidebar: { open: true } }, invalid data falls back to defaults
const theme = createWebStorageValue({
type: 'localStorage',
key: 'theme',
schema: z.enum(['light', 'dark']),
defaultValue: 'light',
}) // single key
theme.set('light')import { createCookieValue } from 'seitu/web'
import * as z from 'zod'
const lang = createCookieValue({
key: 'lang',
schema: z.enum(['en', 'fr']),
defaultValue: 'en',
getServerCookies: () => requestCookieHeader, // the framework's `Cookie` header reader
}) // SSR renders the cookie value, hydration matches it
lang.set('fr')import {
createIndexedDb,
createIndexedDbStorage,
createIndexedDbTable,
} from 'seitu/web'
import * as z from 'zod'
const db = createIndexedDb({
name: 'app',
stores: {
session: createIndexedDbStorage({
schemas: { token: z.string().nullable() },
defaultValues: { token: null },
}), // key/value, sync get() via cache
todos: createIndexedDbTable({
keyPath: 'id',
indexes: { status: 'status' },
schema: z.object({ id: z.string(), status: z.enum(['open', 'done']) }),
}), // rows, validated on write and read
},
}) // one connection, stores created on demand
const { session, todos } = db.stores
await db.ready // open + session hydrated
await session.set({ token: 'abc' })
await todos.put({ id: '1', status: 'open' })
const open = todos.query((t) => t.index('status').getAll('open'), {
initial: [],
}) // reactiveimport { createIsOnline, createMediaQuery, createScrollState } from 'seitu/web'
const isDark = createMediaQuery({ query: '(prefers-color-scheme: dark)' }) // type-checked query
const online = createIsOnline()
const feed = createScrollState({
element: () => document.querySelector('#feed'),
threshold: 200,
})
feed.subscribe(({ bottom }) => bottom.reached && loadMore())// React
import { useSubscription } from 'seitu/react'
function Theme() {
const theme = useSubscription(settings, { selector: (s) => s.theme })
return (
<button
onClick={() =>
settings.set({ theme: theme === 'light' ? 'dark' : 'light' })
}
>
{theme}
</button>
)
}<!-- Vue -->
<script setup lang="ts">
import { useSubscription } from 'seitu/vue'
const theme = useSubscription(settings, { selector: (s) => s.theme })
</script>
<template>
<button
@click="settings.set({ theme: theme === 'light' ? 'dark' : 'light' })"
>
{{ theme }}
</button>
</template>// Solid
import { useSubscription } from 'seitu/solid'
function Theme() {
const theme = useSubscription(settings, { selector: (s) => s.theme })
return (
<button
onClick={() =>
settings.set({ theme: theme() === 'light' ? 'dark' : 'light' })
}
>
{theme()}
</button>
)
}<!-- Svelte -->
<script lang="ts">
import { useSubscription } from 'seitu/svelte'
const theme = useSubscription(settings, { selector: (s) => s.theme })
</script>
<button onclick={() => settings.set({ theme: $theme === 'light' ? 'dark' : 'light' })}>{$theme}</button>Inline creation (elements, props). Use a callback ref so the subscription is rebuilt when the element mounts, unmounts, or remounts:
const [el, setEl] = useState<HTMLDivElement | null>(null)
const scroll = useSubscription(() => createScrollState({ element: el }), {
deps: [el],
})
return <div ref={setEl} />Skills ship inside the npm package and describe the installed version's API.
pnpm dlx @tanstack/intent@latest install
pnpm dlx @tanstack/intent@latest load seitu#seitu-overviewMIT