npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

stroid

v0.1.5

Published

Deterministic state engine for React and JavaScript with SSR-safe isolation, multi-store coordination, and decision-driven state workflows.

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, and prototype.
  • useStore("name") without a path or selector subscribes to the full store. Prefer useSelector(...) or path reads in hot React components.
  • Hook string names are only strongly typed after StoreStateMap augmentation. Without it, useStore("name") reads are intentionally loose and typically resolve to unknown.
  • 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 replayable refetchStore() semantics. Use a URL string or factory when you need retry/backoff behavior.
  • asyncAutoCreate is a development convenience, not a production safety feature. Leave it off in production to avoid typo-created phantom stores.
  • stroid/sync uses same-origin BroadcastChannel transport. 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/persist relies 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 with server_wins, client_wins, merge, or invalidate_and_refetch.
  • React hooks are built on useSyncExternalStore; local concurrency certification now covers no-tearing invariants under useTransition and useDeferredValue.
  • stroid/server is Node-only today because it depends on node:async_hooks. Edge runtimes and Workers need a different adapter.
  • stroid/server/portable is 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 by benchmark:next-server-actions and 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 stroid root 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 bootWindowMs or bootWindow: { 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 merge for filters or preference bags and invalidate_and_refetch for 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 like useStore. 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 /docs directory 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 runtime
  • getHistory(name, limit?) to read recorded store history
  • clearHistory(name?) to clear one store or all stores

Setup:

  1. Install Redux DevTools extension in your browser.
  2. Call installDevtools() once in app entry.
  3. Open browser DevTools and inspect the connected stroid session.

🍕 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), plus configureStroid, 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) and RegistryScope.
  • 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() and getStoreSnapshotNoTrack()
  • Committed-final observation: subscribeStore()
  • Serializable writes: applyStorePatch() and applyStorePatchesAtomic() with set, merge, delete, and insert
  • Runtime inspection: getRuntimeGraph(), getComputedDescriptor(), evaluateComputed(), and getTimingContract()

See Native PSR Contract for full details.


📘 Docs

Full documentation in /docs:


📝 Changelog & License

Made with care for developers who think about state seriously.

⭐ Star on GitHub · 🐛 Report a bug · 💬 Discussions