stroid
v0.1.5
Published
Deterministic state engine for React and JavaScript with SSR-safe isolation, multi-store coordination, and decision-driven state workflows.
Maintainers
Readme
Stroid is the only state management library with a theoretical correctness argument, a matching implementation, and a certified benchmark suite proving it holds under production-grade concurrent SSR conditions.
🟣 Stroid - State Engine for TypeScript and React
Named-store state engine for TypeScript and React.
Every store has a name. Write to it from anywhere: hooks, utilities, server, tests. Optional layers add persistence, sync, async fetch, SSR isolation, post-hydration consistency controls, and devtools without coupling to core logic. Get Started | Why Stroid | API Reference | PSR | DevTools | Examples
Certified benchmark suite (latest rerun: 2026-04-02)
0 SSR correctness violations across 2 x 1,024 burst requests, 8,192 sustained requests, and 256 concurrent React streaming SSR requests, plus 0 detached leaks in warm-container/provider-model runs and 0 React concurrency invariant violations under useTransition and useDeferredValue.
Benchmark Report | Run: npm run benchmark:guarantees
[!IMPORTANT]
🧠 What Is Stroid?
A structured state management system focused on predictability, SSR safety, and debugging clarity.
- Core store runtime (
createStore,setStore,getStore)- React hooks (
useStore,useSelector)- Async fetch/cache/revalidate
- Optional features
- SSR request isolation
- Native PSR contract
⚡ 30-Second Quickstart
[!NOTE]
npm install stroid
[!NOTE]
import { createStore, setStore, getStore, configureStroid } from "stroid"; import { installPersist } from "stroid/persist"; import { installSync } from "stroid/sync"; configureStroid({ asyncAutoCreate: false, defaultSnapshotMode: "deep", }); installPersist(); installSync(); //create store createStore("auth", { user: null, token: null }); //create store with persist createStore("settings", { theme: "dark" }, { persist: true }); //create store with sync and persist. createStore("session", { active: true }, { persist: true, sync: true }); setStore("auth", "user", { id: "u1", name: "Asha" }); const auth = getStore("auth");
Operational Notes
- Store names are runtime-validated. Avoid spaces and reserved keys like
__proto__,constructor, andprototype. useStore("name")without a path or selector subscribes to the full store. PreferuseSelector(...)or path reads in hot React components.- Hook string names are only strongly typed after
StoreStateMapaugmentation. Without it,useStore("name")reads are intentionally loose and typically resolve tounknown. - Selector-heavy dev flows that read frozen state deep-clone by default for safe dependency tracking. If that overhead matters more than the extra safety, tune
selectorCloneFrozen. fetchStore(name, promise, ...)accepts a direct Promise, but direct Promise inputs cannot use retries or replayablerefetchStore()semantics. Use a URL string or factory when you need retry/backoff behavior.asyncAutoCreateis a development convenience, not a production safety feature. Leave it off in production to avoid typo-created phantom stores.stroid/syncuses same-originBroadcastChanneltransport. Stroid requests a fresh snapshot on startup, focus, and reconnect, but listener registration can still race under load,policy: "insecure"is an explicit opt-out, and open channels may reduce BFCache restores.stroid/persistrelies on browser storage.checksum: "hash"is non-cryptographic, and Safari/WebKit can evict script-writable storage after roughly 7 days of inactivity, so persisted auth, carts, and drafts should have a server-backed recovery path.hydrateStores(snapshot, options, trust, consistency?)can add a bounded post-hydration consistency window. Stroid can defer early client writes, emit structured drift events, and reconcile per store withserver_wins,client_wins,merge, orinvalidate_and_refetch.- React hooks are built on
useSyncExternalStore; local concurrency certification now covers no-tearing invariants underuseTransitionanduseDeferredValue. stroid/serveris Node-only today because it depends onnode:async_hooks. Edge runtimes and Workers need a different adapter.stroid/server/portableis the explicit request-scope boundary for serverless hand-offs, worker-style runtimes, and Server Actions. It does not rely on implicit async context; use the bound scope API it returns.- Local provider-model certification now covers warm AWS Lambda-style Node handlers, Vercel render-to-action hand-off, and Cloudflare Workers-style explicit scopes, but you should still validate against your deployed provider before claiming production certification.
- Next.js Server Actions are a separate execution boundary. They do not inherit the original request carrier automatically; capture state on render and resume it with
stroid/server/portable. The render-to-action hand-off is covered bybenchmark:next-server-actionsand examples/next-app-router-server-actions.ts. - Stroid can only guarantee request isolation for state written through Stroid APIs. Third-party singleton stores remain outside that guarantee.
Stroid PSR
Stroid ships a native PSR contract in stroid/psr.
It exposes committed snapshots, patch application APIs, and runtime graph/timing data used for governance flows.
🗺️ Ecosystem Map
Stroid is organized into focused sub-packages. Import only what you need.
stroid <- core public runtime
|- stroid/react <- React hooks
|- stroid/core <- minimal core surface
|- stroid/psr <- native PSR contract
|- stroid/async <- fetch/cache/revalidate
|- stroid/query <- reactQueryKey(), swrKey()
|- stroid/selectors <- selector helpers
|- stroid/computed <- computed stores
|- stroid/persist <- installPersist()
|- stroid/sync <- installSync()
|- stroid/devtools <- installDevtools(), history API
|- stroid/server <- SSR request-scoped registry
|- stroid/server/portable <- explicit request-scope bridge for serverless / workers / server actions
|- stroid/helpers <- entity/list/counter helpers
|- stroid/testing <- test helpers
|- stroid/runtime-tools <- observability APIs
|- stroid/runtime-admin <- clear helpers
|- stroid/feature <- feature plugin API
|- stroid/install <- installAllFeatures()Import note:
- Prefer subpath imports and avoid defaulting to the full
stroidroot import unless you need its broader compatibility surface.
🤔 Why Stroid?
Honest comparison
| Feature | Stroid | Redux Toolkit | Zustand | Jotai | Valtio | |---|:---:|:---:|:---:|:---:|:---:| | Write without reducers | ✅ | ❌ | ✅ | ✅ | ✅ | | Named global stores | ✅ | ✅ | ⚠️ manual | ❌ | ❌ | | Write governance (PSR) | ✅ | ❌ | ❌ | ❌ | ❌ | | Built-in DevTools extension | ✅ | ✅ | ⚠️ limited | ❌ | ❌ | | Computed / derived state | ✅ | ✅ | ⚠️ manual | ✅ | ✅ | | Async data built-in | ✅ | ✅ RTK Query | ❌ | ⚠️ | ❌ | | SSR / request isolation | ✅ | ⚠️ | ⚠️ | ✅ | ⚠️ | | Atomic rollback guarantee | ✅ | ❌ | ❌ | ❌ | ❌ | | Race resistance proof | ✅ | ❌ | ❌ | ❌ | ❌ | | Determinism replay | ✅ | ❌ | ❌ | ❌ | ❌ | | Ring-buffer event timeline | ✅ | ❌ | ❌ | ❌ | ❌ | | TypeScript-first | ✅ | ✅ | ✅ | ✅ | ✅ |
⚠️ = possible with extra setup · ❌ = not supported natively
Stroid exposes governance-oriented write flows through stroid/psr, including committed snapshot reads, patch application APIs, runtime graph inspection, and timing contracts.
Benchmark report: docs/STROID/BENCHMARK.md.
Benchmark script layout is categorized by domain under scripts/core, scripts/ssr, scripts/hydration, scripts/react, scripts/guarantees, and scripts/comparison.
Stroid is a fit when you need these together:
- Named global stores with direct writes
- Optional feature installs instead of mandatory side effects
- Strict hydration trust gate (
hydrateStores(..., ..., { allowTrusted: true })) - Governed post-hydration drift handling with per-store consistency policies
- Request-scoped SSR runtime (
createStoreForRequest) with server guards - PSR-style patch application and runtime graph inspection (
stroid/psr)
If you only need ultra-minimal local state, stroid/core exists for a smaller surface.
📚 Full API Reference
All examples use real APIs from this repository's current source.
⚙️ Core - stroid
createStore
import { createStore } from "stroid";
createStore("cart", {
items: [],
total: 0,
});Creates a named store and registers its initial state.
setStore
import { setStore } from "stroid";
setStore("cart", "total", 499);
setStore("cart", { currency: "NPR" });
setStore("cart", (draft: any) => {
draft.items.push({ id: "pizza", qty: 1 });
});Updates existing store state by path, partial object merge, or mutator function.
The public root API intentionally does not export replaceStore; explicit full-store replacement is kept on the internal runtime/PSR side to reduce accidental overwrite mistakes.
getStore
import { getStore } from "stroid";
const cart = getStore("cart");
const total = getStore("cart", "total");Reads current store state, optionally at a nested path.
hasStore
import { hasStore, createStore } from "stroid";
if (!hasStore("cart")) {
createStore("cart", { items: [], total: 0 });
}Checks whether a store is already registered.
resetStore
import { resetStore } from "stroid";
resetStore("cart");Resets a store back to its original initial state.
Reset clone behavior is configurable:
- Per store:
createStore("cart", initial, { resetClone: "deep" | "shallow" | "none" }) - Global default:
configureStroid({ resetCloneMode: "deep" | "shallow" | "none" })
deleteStore
import { deleteStore } from "stroid";
deleteStore("cart");Removes a store and its runtime metadata/subscriptions.
setStoreBatch
import { setStoreBatch, setStore } from "stroid";
setStoreBatch(() => {
setStore("checkout", "coupon", "SAVE20");
setStore("checkout", "deliveryType", "priority");
setStore("checkout", "tip", 50);
});setStoreBatch accepts only synchronous callbacks.
Runs multiple synchronous writes in one transaction-style batch.
hydrateStores
import { hydrateStores } from "stroid";
const hydration = hydrateStores(
{
cart: { items: [{ id: "pizza", qty: 1 }], total: 499 },
profile: { name: "Asha" },
},
{},
{ allowTrusted: true },
{
contract: {
snapshotVersion: 3,
timestamp: Date.now(),
stores: {
cart: { authority: "server-authoritative" },
profile: { authority: "client-authoritative" },
},
},
bootWindow: {
mode: "manual",
fallbackMs: 3000,
},
policyMap: {
cart: "server_wins",
profile: "client_wins",
},
}
);
hydration.bootWindow?.close();Hydrates many stores from a trusted snapshot payload. The optional fourth argument adds post-hydration drift controls, write deferral during the boot window, and structured drift diagnostics. Manual mode returns hydration.bootWindow, so your app can close the gate when its critical hydration boundary is ready.
Recommended rollout defaults:
- use
bootWindow: { mode: "manual", fallbackMs: 3000 }when you need certification-grade control - keep
bootWindowMsorbootWindow: { mode: "timer", ms: ... }only as a compatibility fallback when you cannot close manually yet - keep auth/session stores
server_wins - keep drafts/forms
client_wins - use
mergefor filters or preference bags andinvalidate_and_refetchfor replayable async caches
The full adoption guide, policy defaults, and runtime-tools workflow live in Post-Hydration Consistency.
configureStroid
import { configureStroid } from "stroid";
configureStroid({
asyncAutoCreate: false,
strictMutatorReturns: true,
defaultSnapshotMode: "deep",
});Sets global runtime behavior such as async and snapshot defaults.
[!TIP]
Stroid is NOT for:
- small apps
- simple UI state
- beginners learning React
Stroid is for:
- complex apps
- SSR-heavy systems
- multi-source async data
- teams that need debugging + guarantees *If Still want to learn, then:
- Beginners: If you are building a personal portfolio or a small app, you likely only need
createStore,getStore, and the basic React hooks likeuseStore. I don't want you to read whole README.- Intermediate: We recommend reading the full README to understand features like batching, persistence,SSR Isolation,Sync,and async fetching. Don't take overhead about PSR FOR NOW, THINK THAT NOT EXIST AT ALL. UNTIL, I MAKE PROPER EXPLANATION VIDEO.
- Advanced: Explore the
/docsdirectory for deep dives into architecture, SSR isolation, and the PSR contract, DevTools.
⚛️ React Hooks - stroid/react
useStore
import { useStore } from "stroid/react";
function CartPanel() {
const cart = useStore("cart");
return <div>{cart ? `${cart.items.length} items` : "Cart empty"}</div>;
}Subscribes React components to a store value (full store, path, or selector form).
useSelector
import { useSelector } from "stroid/react";
function CartTotal() {
const total = useSelector("cart", (s: any) => s?.total ?? 0);
return <strong>Rs. {total}</strong>;
}Subscribes to a derived slice and re-renders only when selected output changes.
useStoreField
import { useStoreField } from "stroid/react";
function DeliveryTypeChip() {
const deliveryType = useStoreField("checkout", "deliveryType");
return <span>{deliveryType ?? "standard"}</span>;
}Subscribes directly to one field/path inside a store.
useStoreStatic
import { useStoreStatic } from "stroid/react";
function DebugPanel() {
const snapshot = useStoreStatic("cart");
return <pre>{JSON.stringify(snapshot, null, 2)}</pre>;
}Reads a snapshot once without live subscription updates.
useAsyncStore
import { useEffect } from "react";
import { useAsyncStore } from "stroid/react";
import { fetchStore } from "stroid/async";
function Menu() {
useEffect(() => {
void fetchStore("menu", "https://api.example.com/menu", { autoCreate: true });
}, []);
const { loading, error, data } = useAsyncStore("menu");
if (loading) return <p>Loading menu...</p>;
if (error) return <p>Failed to load menu</p>;
return <MenuList items={data ?? []} />;
}Reads async store shape (data/loading/error/status) from an existing store.
useAsyncStoreSuspense
import { useAsyncStoreSuspense } from "stroid/react";
function MenuSuspense() {
const menu = useAsyncStoreSuspense<Array<{ id: string; name: string }>>(
"menu",
"https://api.example.com/menu",
{ autoCreate: true }
);
return <MenuList items={menu} />;
}Integrates async store reads with React Suspense by throwing pending work.
useFormStore
import { createStore } from "stroid";
import { useFormStore } from "stroid/react";
createStore("loginForm", { email: "", password: "" });
function LoginForm() {
const email = useFormStore("loginForm", "email");
const password = useFormStore("loginForm", "password");
return (
<form>
<input value={email.value ?? ""} onChange={email.onChange} />
<input value={password.value ?? ""} onChange={password.onChange} type="password" />
<button disabled={!email.value || !password.value}>Sign in</button>
</form>
);
}Binds a store field to form-style value and onChange helpers.
RegistryScope
import { RegistryScope } from "stroid/react";
function App({ registry }: { registry: any }) {
return (
<RegistryScope value={registry}>
<CartPanel />
<ProfilePanel />
</RegistryScope>
);
}Scopes a React subtree to a specific store registry context.
𛲝Se Selectors & Computed
createSelector - stroid/selectors
import { createSelector } from "stroid/selectors";
const selectItemCount = createSelector("cart", (s: any) => s?.items?.length ?? 0);
const count = selectItemCount();Builds a memoized selector function for derived store reads.
subscribeWithSelector - stroid/selectors
import { subscribeWithSelector } from "stroid/selectors";
const stop = subscribeWithSelector(
"cart",
(s: any) => s?.total,
Object.is,
(next, prev) => {
if (typeof prev === "number" && next > prev) {
// run side effect
}
}
);
stop();Runs a listener only when the selected value changes by equality check.
createComputed - stroid/computed
import { createComputed } from "stroid/computed";
import { getStore } from "stroid";
createComputed("deliveryFee", ["cart"], (cart: any) => (cart?.total ?? 0) > 1000 ? 0 : 60);
const fee = getStore("deliveryFee");Creates a computed store derived from one or more dependency stores.
invalidateComputed / deleteComputed / isComputedStore
import { invalidateComputed, deleteComputed, isComputedStore } from "stroid/computed";
invalidateComputed("deliveryFee");
deleteComputed("deliveryFee");
isComputedStore("deliveryFee");Invalidates, removes, or checks computed-store registrations.
⏱️ Async - stroid/async
import { fetchStore, refetchStore, enableRevalidateOnFocus } from "stroid/async";
await fetchStore("menu", "https://api.example.com/menu");
await refetchStore("menu");
const stopFocusRevalidate = enableRevalidateOnFocus("menu");
stopFocusRevalidate();Fetches/refetches remote data into stores with cache, dedupe, retries, and focus revalidation.
PSR - Write Governance
import { applyStorePatch, applyStorePatchesAtomic } from "stroid/psr";
applyStorePatch({
id: "cart-total-set",
store: "cart",
path: ["total"],
op: "set",
value: 549,
meta: { timestamp: Date.now(), source: "setStore" },
});
applyStorePatchesAtomic([
{
id: "wallet-set",
store: "wallet",
path: ["balance"],
op: "set",
value: 900,
meta: { timestamp: Date.now(), source: "setStore" },
},
{
id: "order-set",
store: "order",
path: ["status"],
op: "set",
value: "paid",
meta: { timestamp: Date.now(), source: "setStore" },
},
]);Applies patch-based governed writes with atomic multi-patch support.
🛡️ Features - stroid/feature
Install - Opt-In Capabilities
import { installPersist } from "stroid/persist";
import { installSync } from "stroid/sync";
import { installDevtools } from "stroid/devtools";
installPersist();
installSync();
installDevtools();Installs optional persist/sync/devtools features explicitly at app entry.
🌐 SSR - stroid/server
import { createStoreForRequest } from "stroid/server";
const requestScope = createStoreForRequest((api) => {
api.create("session", { userId: "u-1" });
api.create("cart", { items: [], total: 0 });
});
const html = requestScope.hydrate(() => renderToString(<App />));
const snapshot = requestScope.snapshot();Creates per-request store scopes for SSR-safe hydrate/snapshot flows.
🔢 Helpers - stroid/helpers
import { createEntityStore, createListStore, createCounterStore } from "stroid/helpers";
const users = createEntityStore<{ id?: string; name: string }>("users");
users.upsert({ id: "u1", name: "Asha" });
users.remove("u1");
const tasks = createListStore("tasks", [] as string[]);
tasks.push("pick up order");
tasks.removeAt(0);
tasks.clear();
const retries = createCounterStore("retries", 0);
retries.inc();
retries.dec();
retries.set(5);
const retryValue = retries.get();Provides ready-made entity, list, and counter store helpers.
🧪 Testing - stroid/testing
import { store } from "stroid";
import {
createMockStore,
resetAllStoresForTest,
withMockedTime,
benchmarkStoreSet,
} from "stroid/testing";
const mockOrder = createMockStore("order", { status: "draft" });
mockOrder.set({ status: "confirmed" });
withMockedTime(1700000000000, () => {
// Date.now() is fixed in this callback
});
const result = benchmarkStoreSet(store("cart"), 300);
const avgMs = result.avgMs;
resetAllStoresForTest();Provides test helpers for mock stores, time control, reset, and micro-benchmarks.
📈 Runtime Observability - stroid/runtime-tools
import {
listStores,
getStoreMeta,
getMetrics,
getSubscriberCount,
getStoreHealth,
findColdStores,
getComputedGraph,
getComputedDeps,
getPersistQueueDepth,
} from "stroid/runtime-tools";
const stores = listStores();
const meta = getStoreMeta("cart");
const metrics = getMetrics("cart");
const subscribers = getSubscriberCount("cart");
const health = getStoreHealth();
const cold = findColdStores();
const graph = getComputedGraph();
const deps = getComputedDeps("deliveryFee");
const persistDepth = getPersistQueueDepth("cart");Exposes runtime diagnostics for stores, metrics, health, and computed graph state. Import only the functions you need. The internal helpers are grouped more narrowly now, but the published multi-entry build still shares runtime chunks, so the biggest remaining wins are still deeper than this surface split.
🗝️ Query Keys - stroid/query
import { reactQueryKey, swrKey } from "stroid/query";
const tanstackKey = reactQueryKey("cart");
const swrCacheKey = swrKey("cart", "summary");Use stroid/query when you only need stable cache keys for TanStack Query or SWR.
The root queryIntegrations namespace still exists for compatibility, but stroid/query is the leaner path.
🔧 Runtime Admin - stroid/runtime-admin
import { clearAllStores, clearStores } from "stroid/runtime-admin";
clearStores("cart*");
clearAllStores();Clears stores in bulk by pattern or globally.
🌉 DevTools Bridge - stroid/devtools
import { installDevtools, getHistory, clearHistory } from "stroid/devtools";
installDevtools();
const cartHistory = getHistory("cart");
// Array<HistoryEntry> where entry has: ts, action, prev, next, diff
clearHistory("cart");Connects to devtools runtime and exposes local history read/clear APIs.
🔌 Feature Plugin API - stroid/feature
import {
registerStoreFeature,
hasRegisteredStoreFeature,
getRegisteredFeatureNames,
} from "stroid/feature";
registerStoreFeature("auditFeature", () => ({
onStoreCreate(ctx) {
// fires when a store is created
},
onStoreWrite(ctx) {
// fires on store write
},
}));
const hasAudit = hasRegisteredStoreFeature("auditFeature");
const featureNames = getRegisteredFeatureNames();Registers custom feature runtimes with lifecycle hooks.
🛡️ PSR - Write Governance - stroid/psr
PSR (stroid/psr) is the public contract for:
- Committed snapshots
- Post-commit subscriptions
- Serializable patch application
- Runtime graph and timing contract inspection
PSR API
import {
getStoreSnapshot,
getStoreSnapshotNoTrack,
subscribeStore,
applyStorePatch,
applyStorePatchesAtomic,
getRuntimeGraph,
getComputedDescriptor,
evaluateComputed,
getTimingContract,
} from "stroid/psr";
const committed = getStoreSnapshot("cart");
const committedNoTrack = getStoreSnapshotNoTrack("cart");
const unsubscribe = subscribeStore("cart", (next) => {
// handle committed updates
});
const graph = getRuntimeGraph();
const checkoutNode = graph.nodes.find(
(n) => n.storeId === "checkoutTotal" && (n.type === "computed" || n.type === "async-boundary")
);
if (checkoutNode) {
const descriptor = getComputedDescriptor(checkoutNode.id);
const preview = evaluateComputed(checkoutNode.id, {
cart: { items: [{ id: "pizza", qty: 2 }], total: 998 },
});
}
const timing = getTimingContract("cart");Exposes committed snapshots, subscriptions, patch APIs, runtime graph, and timing contract.
🔬 DevTools - stroid/devtools
stroid/devtools integrates with the Redux DevTools browser extension and also keeps in-memory history per store.
What you get from code:
installDevtools()to enable the devtools feature runtimegetHistory(name, limit?)to read recorded store historyclearHistory(name?)to clear one store or all stores
Setup:
- Install Redux DevTools extension in your browser.
- Call
installDevtools()once in app entry. - Open browser DevTools and inspect the connected
stroidsession.
🍕 Real-World Examples
Food delivery cart (full flow)
// app/entry.ts
import { configureStroid } from "stroid";
import { installPersist } from "stroid/persist";
import { installDevtools } from "stroid/devtools";
configureStroid({ asyncAutoCreate: false });
installPersist();
installDevtools();
// stores/cart.ts
import { createStore, setStoreBatch, setStore } from "stroid";
createStore("cart", { items: [], total: 0 });
createStore("checkout", { coupon: null, deliveryType: "standard", tip: 0 });
// components/CartPanel.tsx
import { useSelector, useStoreField } from "stroid/react";
function CartPanel() {
const total = useSelector("cart", (s: any) => s?.total ?? 0);
const deliveryType = useStoreField("checkout", "deliveryType");
function applyPromo() {
setStoreBatch(() => {
setStore("checkout", "coupon", "SAVE20");
setStore("checkout", "deliveryType", "priority");
setStore("checkout", "tip", 50);
});
}
return (
<div>
<p>Total: Rs. {total}</p>
<p>Delivery: {deliveryType}</p>
<button onClick={applyPromo}>Apply promo</button>
</div>
);
}Atomic payment (wallet + order status)
import { getStore } from "stroid";
import { applyStorePatchesAtomic } from "stroid/psr";
function confirmPayment(amount: number) {
const wallet = getStore("wallet") as { balance: number } | null;
const nextBalance = (wallet?.balance ?? 0) - amount;
applyStorePatchesAtomic([
{
id: "pay-wallet",
store: "wallet",
path: ["balance"],
op: "set",
value: nextBalance,
meta: { timestamp: Date.now(), source: "setStore" },
},
{
id: "pay-order",
store: "order",
path: ["status"],
op: "set",
value: "paid",
meta: { timestamp: Date.now(), source: "setStore" },
},
]);
}Applies related wallet/order updates atomically so both succeed or fail together.
Menu with Suspense
import { Suspense } from "react";
import { useAsyncStoreSuspense } from "stroid/react";
function MenuList() {
const menu = useAsyncStoreSuspense<Array<{ id: string; name: string }>>(
"menu",
"https://api.example.com/menu",
{ autoCreate: true }
);
return <ul>{menu.map((item) => <li key={item.id}>{item.name}</li>)}</ul>;
}
export function MenuPage() {
return (
<Suspense fallback={<p>Loading menu...</p>}>
<MenuList />
</Suspense>
);
}Loads menu data through Suspense-friendly async store access.
🧱 Layer Map
+---------------------------------------------------------+
| your app |
+---------------------------------------------------------+
| useStore useSelector useAsyncStore useFormStore | stroid/react
+---------------------------------------------------------+
| createStore setStore getStore setStoreBatch | stroid
| createComputed createSelector createEntityStore |
+--------------+--------------+---------------------------+
| stroid/persist | stroid/sync | stroid/async |
| installPersist | installSync | fetch + cache + retry |
+--------------+--------------+---------------------------+
| stroid/server createStoreForRequest | SSR
+---------------------------------------------------------+
| stroid/devtools stroid/testing stroid/runtime-tools |
+---------------------------------------------------------+Each row is independent. Use only what you need.
stroid/core exports only createStore, setStore, getStore, hasStore, resetStore, and deleteStore.
Import from stroid for batching/hydration/computed plus runtime metrics and config.
📦 What Each Import Contains
stroid: Core public runtime (createStore,createStoreStrict,setStore,setStoreBatch,getStore,deleteStore,resetStore,hasStore,hydrateStores), plusconfigureStroid, computed helpers, and health/metric helpers.stroid/psr: PSR contract (getStoreSnapshot,getStoreSnapshotNoTrack,subscribeStore,applyStorePatch,applyStorePatchesAtomic, runtime graph/timing helpers).stroid/core: Minimal CRUD runtime (createStore,setStore,getStore,hasStore,resetStore,deleteStore).stroid/react: React hooks (useStore,useSelector,useStoreField,useStoreStatic,useAsyncStore,useFormStore,useAsyncStoreSuspense) andRegistryScope.stroid/async: Async APIs (fetchStore,refetchStore,enableRevalidateOnFocus,getAsyncMetrics).stroid/query: cache-key helpers (reactQueryKey,swrKey) without the fetcher helpers.stroid/selectors:createSelector,subscribeWithSelector.stroid/computed:createComputed,invalidateComputed,deleteComputed,isComputedStore.stroid/persist:installPersist.stroid/sync:installSync.stroid/devtools:installDevtools,getHistory,clearHistory.stroid/server:createStoreForRequest.stroid/helpers:createEntityStore,createListStore,createCounterStore.stroid/testing:createMockStore,resetAllStoresForTest,withMockedTime,benchmarkStoreSet.stroid/runtime-tools: Store/runtime observability APIs, including hydration drift reports and counters.stroid/runtime-admin:clearAllStores,clearStores.stroid/feature: Feature registration APIs.stroid/install:installPersist,installSync,installDevtools,installAllFeatures.
🧾 Quick API Reference
| API | Purpose |
|-----|---------|
| createStore(name, state, options?) | Define a store. Returns StoreDefinition or undefined. |
| createStoreStrict(name, state, options?) | Define a store; throws if creation fails. |
| setStore(name, update) | Merge object update into object store state. |
| setStore(name, path, value) | Write by path. |
| setStore(name, draft => { ... }) | Mutator-style update. |
| getStore(name, path?) | Read current state (or nested path). |
| deleteStore(name) | Remove a store from registry. |
| resetStore(name) | Restore initial state. |
| hasStore(name) | Check if store exists. |
| setStoreBatch(fn) | Group synchronous writes into one transaction. |
| hydrateStores(snapshot, options?, trust, consistency?) | Hydrate trusted snapshot into runtime, optionally governing post-hydration drift. |
| configureStroid(config) | Configure global/runtime behavior. |
| useStore(name, selectorOrPath?) | React subscription hook. |
| useSelector(name, fn, equality?) | Fine-grained React selector hook. |
| fetchStore(name, input, options?) | Fetch remote data into store. |
| getAsyncMetrics(name?) | Read global or per-store async counters. |
| createComputed(name, deps, fn) | Define computed store. |
| createStoreForRequest(fn) | Build SSR request-scoped store runtime. |
🧭 Module Import Map
// Core
import {
createStore,
createStoreStrict,
setStore,
getStore,
hasStore,
deleteStore,
resetStore,
setStoreBatch,
hydrateStores,
configureStroid,
} from "stroid";
// Native PSR contract
import {
getStoreSnapshot,
getStoreSnapshotNoTrack,
subscribeStore,
applyStorePatch,
applyStorePatchesAtomic,
getRuntimeGraph,
getComputedDescriptor,
evaluateComputed,
getTimingContract,
} from "stroid/psr";
// Minimal core (subpath import)
import { createStore, setStore, getStore, hasStore, resetStore, deleteStore } from "stroid/core";
// React
import {
useStore,
useSelector,
useStoreField,
useStoreStatic,
useAsyncStore,
useFormStore,
useAsyncStoreSuspense,
RegistryScope,
} from "stroid/react";
// Async
import { fetchStore, refetchStore, enableRevalidateOnFocus } from "stroid/async";
// Query keys only
import { reactQueryKey, swrKey } from "stroid/query";
// Selectors & Computed
import { createSelector, subscribeWithSelector } from "stroid/selectors";
import { createComputed, invalidateComputed, deleteComputed, isComputedStore } from "stroid/computed";
// Features (explicit install - call once at app entry)
import { installPersist } from "stroid/persist";
import { installSync } from "stroid/sync";
import { installDevtools, getHistory, clearHistory } from "stroid/devtools";
installPersist();
installSync();
installDevtools();
// Server / SSR
import { createStoreForRequest } from "stroid/server";
// Helpers & Testing
import { createEntityStore, createListStore, createCounterStore } from "stroid/helpers";
import { createMockStore, resetAllStoresForTest, withMockedTime, benchmarkStoreSet } from "stroid/testing";
// Runtime Observability + Admin
import {
listStores,
getStoreMeta,
getMetrics,
getSubscriberCount,
getStoreHealth,
findColdStores,
getComputedGraph,
getComputedDeps,
getPersistQueueDepth,
} from "stroid/runtime-tools";
import { clearAllStores, clearStores } from "stroid/runtime-admin";
// Feature plugin API
import { registerStoreFeature, hasRegisteredStoreFeature, getRegisteredFeatureNames } from "stroid/feature";
// Optional all-in-one installer
import { installAllFeatures } from "stroid/install";🧷 Native PSR Contract
stroid/psr is the supported public surface for native PSR-style integration.
- Committed reads:
getStoreSnapshot()andgetStoreSnapshotNoTrack() - Committed-final observation:
subscribeStore() - Serializable writes:
applyStorePatch()andapplyStorePatchesAtomic()withset,merge,delete, andinsert - Runtime inspection:
getRuntimeGraph(),getComputedDescriptor(),evaluateComputed(), andgetTimingContract()
See Native PSR Contract for full details.
📘 Docs
Full documentation in /docs:
- Architecture - layers, data flow, registry model
- Core Concepts - store lifecycle, options, write modes
- React Layer - hooks, selectors, SSR
- Async Layer -
fetchStore, caching, revalidation - Persistence - persist options, encryption, migrations
- Cross-tab Sync - BroadcastChannel sync behavior
- Computed Stores - reactive derived values
- Native PSR Contract - patch coverage, timing/governance, graph identity
- Server & SSR - request-scoped stores, hydration
- Testing - mock stores, resets, benchmarks
- Runtime Tools - observability, health checks
- TypeScript Guide
- Full API Reference
- Project Status
- Contributing
📝 Changelog & License
Made with care for developers who think about state seriously.
