stroid 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +375 -468
  3. package/dist/_tsup-dts-rollup.d.cts +2411 -0
  4. package/dist/_tsup-dts-rollup.d.ts +2411 -0
  5. package/dist/async.cjs +29 -24
  6. package/dist/async.cjs.map +1 -0
  7. package/dist/async.d.cts +9 -40
  8. package/dist/async.d.ts +9 -40
  9. package/dist/async.js +29 -24
  10. package/dist/async.js.map +1 -0
  11. package/dist/computed.cjs +12 -10
  12. package/dist/computed.cjs.map +1 -0
  13. package/dist/computed.d.cts +7 -29
  14. package/dist/computed.d.ts +7 -29
  15. package/dist/computed.js +12 -10
  16. package/dist/computed.js.map +1 -0
  17. package/dist/core.cjs +17 -23
  18. package/dist/core.cjs.map +1 -0
  19. package/dist/core.d.cts +15 -5
  20. package/dist/core.d.ts +15 -5
  21. package/dist/core.js +17 -23
  22. package/dist/core.js.map +1 -0
  23. package/dist/devtools.cjs +2 -1
  24. package/dist/devtools.cjs.map +1 -0
  25. package/dist/devtools.d.cts +5 -19
  26. package/dist/devtools.d.ts +5 -19
  27. package/dist/devtools.js +2 -1
  28. package/dist/devtools.js.map +1 -0
  29. package/dist/feature.cjs +2 -0
  30. package/dist/feature.cjs.map +1 -0
  31. package/dist/feature.d.cts +14 -0
  32. package/dist/feature.d.ts +14 -0
  33. package/dist/feature.js +2 -0
  34. package/dist/feature.js.map +1 -0
  35. package/dist/helpers.cjs +17 -13
  36. package/dist/helpers.cjs.map +1 -0
  37. package/dist/helpers.d.cts +3 -29
  38. package/dist/helpers.d.ts +3 -29
  39. package/dist/helpers.js +17 -13
  40. package/dist/helpers.js.map +1 -0
  41. package/dist/index.cjs +26 -21
  42. package/dist/index.cjs.map +1 -0
  43. package/dist/index.d.cts +33 -130
  44. package/dist/index.d.ts +33 -130
  45. package/dist/index.js +26 -21
  46. package/dist/index.js.map +1 -0
  47. package/dist/install.cjs +2 -0
  48. package/dist/install.cjs.map +1 -0
  49. package/dist/install.d.cts +4 -0
  50. package/dist/install.d.ts +4 -0
  51. package/dist/install.js +2 -0
  52. package/dist/install.js.map +1 -0
  53. package/dist/persist.cjs +2 -1
  54. package/dist/persist.cjs.map +1 -0
  55. package/dist/persist.d.cts +1 -2
  56. package/dist/persist.d.ts +1 -2
  57. package/dist/persist.js +2 -1
  58. package/dist/persist.js.map +1 -0
  59. package/dist/react.cjs +27 -22
  60. package/dist/react.cjs.map +1 -0
  61. package/dist/react.d.cts +7 -52
  62. package/dist/react.d.ts +7 -52
  63. package/dist/react.js +27 -22
  64. package/dist/react.js.map +1 -0
  65. package/dist/runtime-admin.cjs +2 -1
  66. package/dist/runtime-admin.cjs.map +1 -0
  67. package/dist/runtime-admin.d.cts +2 -4
  68. package/dist/runtime-admin.d.ts +2 -4
  69. package/dist/runtime-admin.js +2 -1
  70. package/dist/runtime-admin.js.map +1 -0
  71. package/dist/runtime-tools.cjs +3 -2
  72. package/dist/runtime-tools.cjs.map +1 -0
  73. package/dist/runtime-tools.d.cts +9 -39
  74. package/dist/runtime-tools.d.ts +9 -39
  75. package/dist/runtime-tools.js +3 -2
  76. package/dist/runtime-tools.js.map +1 -0
  77. package/dist/selectors.cjs +2 -1
  78. package/dist/selectors.cjs.map +1 -0
  79. package/dist/selectors.d.cts +2 -4
  80. package/dist/selectors.d.ts +2 -4
  81. package/dist/selectors.js +2 -1
  82. package/dist/selectors.js.map +1 -0
  83. package/dist/server.cjs +11 -9
  84. package/dist/server.cjs.map +1 -0
  85. package/dist/server.d.cts +2 -14
  86. package/dist/server.d.ts +2 -14
  87. package/dist/server.js +11 -9
  88. package/dist/server.js.map +1 -0
  89. package/dist/sync.cjs +2 -1
  90. package/dist/sync.cjs.map +1 -0
  91. package/dist/sync.d.cts +1 -2
  92. package/dist/sync.d.ts +1 -2
  93. package/dist/sync.js +2 -1
  94. package/dist/sync.js.map +1 -0
  95. package/dist/testing.cjs +17 -13
  96. package/dist/testing.cjs.map +1 -0
  97. package/dist/testing.d.cts +4 -16
  98. package/dist/testing.d.ts +4 -16
  99. package/dist/testing.js +17 -13
  100. package/dist/testing.js.map +1 -0
  101. package/package.json +12 -3
  102. package/dist/async-cache-DFHwcBQL.d.cts +0 -52
  103. package/dist/async-cache-DFHwcBQL.d.ts +0 -52
  104. package/dist/computed-BbAZm1Dq.d.cts +0 -17
  105. package/dist/computed-CccdgY5j.d.ts +0 -17
  106. package/dist/options-CB35e3Xo.d.cts +0 -245
  107. package/dist/options-CB35e3Xo.d.ts +0 -245
  108. package/dist/types/adapters/options.d.ts +0 -247
  109. package/dist/types/async/clone.d.ts +0 -2
  110. package/dist/types/async/errors.d.ts +0 -3
  111. package/dist/types/async/inflight.d.ts +0 -13
  112. package/dist/types/async/rate.d.ts +0 -5
  113. package/dist/types/async/request.d.ts +0 -3
  114. package/dist/types/async-cache.d.ts +0 -57
  115. package/dist/types/async-fetch.d.ts +0 -37
  116. package/dist/types/async-registry.d.ts +0 -96
  117. package/dist/types/async-retry.d.ts +0 -10
  118. package/dist/types/async.d.ts +0 -2
  119. package/dist/types/computed-graph.d.ts +0 -31
  120. package/dist/types/computed.d.ts +0 -15
  121. package/dist/types/config.d.ts +0 -2
  122. package/dist/types/core.d.ts +0 -1
  123. package/dist/types/devfreeze.d.ts +0 -1
  124. package/dist/types/feature-registry.d.ts +0 -69
  125. package/dist/types/features/lifecycle.d.ts +0 -28
  126. package/dist/types/index.d.ts +0 -6
  127. package/dist/types/integrations/query.d.ts +0 -8
  128. package/dist/types/internals/config.d.ts +0 -62
  129. package/dist/types/internals/diagnostics.d.ts +0 -21
  130. package/dist/types/internals/hooks-warnings.d.ts +0 -6
  131. package/dist/types/internals/reporting.d.ts +0 -8
  132. package/dist/types/internals/store-admin.d.ts +0 -7
  133. package/dist/types/internals/store-ops.d.ts +0 -3
  134. package/dist/types/runtime-admin.d.ts +0 -2
  135. package/dist/types/store-lifecycle/bind.d.ts +0 -3
  136. package/dist/types/store-lifecycle/hooks.d.ts +0 -44
  137. package/dist/types/store-lifecycle/identity.d.ts +0 -23
  138. package/dist/types/store-lifecycle/registry.d.ts +0 -39
  139. package/dist/types/store-lifecycle/types.d.ts +0 -39
  140. package/dist/types/store-lifecycle/validation.d.ts +0 -45
  141. package/dist/types/store-lifecycle.d.ts +0 -20
  142. package/dist/types/store-name.d.ts +0 -19
  143. package/dist/types/store-notify.d.ts +0 -12
  144. package/dist/types/store-read.d.ts +0 -12
  145. package/dist/types/store-registry.d.ts +0 -74
  146. package/dist/types/store-transaction.d.ts +0 -12
  147. package/dist/types/store-write.d.ts +0 -45
  148. package/dist/types/store.d.ts +0 -7
  149. package/dist/types/utils/clone.d.ts +0 -4
  150. package/dist/types/utils/hash.d.ts +0 -8
  151. package/dist/types/utils/path.d.ts +0 -5
  152. package/dist/types/utils/validation.d.ts +0 -14
  153. package/dist/types/utils.d.ts +0 -5
  154. package/dist/types-grvlY4BX.d.cts +0 -37
  155. package/dist/types-grvlY4BX.d.ts +0 -37
package/README.md CHANGED
@@ -1,608 +1,515 @@
1
1
  # Stroid
2
2
 
3
- [![npm](https://img.shields.io/npm/v/stroid)](https://www.npmjs.com/package/stroid)
4
- [![npm downloads](https://img.shields.io/npm/dm/stroid)](https://www.npmjs.com/package/stroid)
3
+ [![npm](https://img.shields.io/npm/v/stroid)](https://npmjs.com/package/stroid)
5
4
  [![bundle size](https://img.shields.io/bundlephobia/minzip/stroid)](https://bundlephobia.com/package/stroid)
6
- [![types](https://img.shields.io/npm/types/stroid)](https://www.npmjs.com/package/stroid)
7
- [![license](https://img.shields.io/npm/l/stroid)](https://github.com/Himesh-Bhattarai/stroid/blob/main/LICENSE)
8
- [![CI](https://img.shields.io/github/actions/workflow/status/Himesh-Bhattarai/stroid/ci.yml?branch=main)](https://github.com/Himesh-Bhattarai/stroid/actions)
9
- [![issues](https://img.shields.io/github/issues/Himesh-Bhattarai/stroid)](https://github.com/Himesh-Bhattarai/stroid/issues)
10
- [![stars](https://img.shields.io/github/stars/Himesh-Bhattarai/stroid)](https://github.com/Himesh-Bhattarai/stroid)
11
- [![forks](https://img.shields.io/github/forks/Himesh-Bhattarai/stroid)](https://github.com/Himesh-Bhattarai/stroid)
12
- [![contributors](https://img.shields.io/github/contributors/Himesh-Bhattarai/stroid)](https://github.com/Himesh-Bhattarai/stroid/graphs/contributors)
13
- [![last commit](https://img.shields.io/github/last-commit/Himesh-Bhattarai/stroid)](https://github.com/Himesh-Bhattarai/stroid/commits/main)
14
- [![commit activity](https://img.shields.io/github/commit-activity/m/Himesh-Bhattarai/stroid)](https://github.com/Himesh-Bhattarai/stroid/commits/main)
15
- [![code size](https://img.shields.io/github/languages/code-size/Himesh-Bhattarai/stroid)](https://github.com/Himesh-Bhattarai/stroid)
16
- [![node](https://img.shields.io/node/v/stroid)](https://www.npmjs.com/package/stroid)
17
-
18
- Stroid is a named-store state library for JavaScript and React. Core stays small; optional layers unlock persist, async caching, sync, and devtools.
19
-
20
- ## Table of Contents
21
-
22
- - [Install](#install)
23
- - [Minimal Usage](#minimal-usage)
24
- - [Module Imports](#module-imports)
25
- - [Stroid At a Glance](#stroid-at-a-glance)
26
- - [Public API Index](#public-api-index)
27
- - [Subpath API Index](#subpath-api-index)
28
- - [Options Index](#options-index)
29
- - [Types Index](#types-index)
30
- - [Behavior Notes](#behavior-notes)
31
- - [Short Recipes](#short-recipes)
32
- - [Docs](#docs)
33
- - [Docs Index (Full)](#docs-index-full)
34
- - [Changelog and License](#changelog-and-license)
5
+ [![types](https://img.shields.io/npm/types/stroid)](https://npmjs.com/package/stroid)
6
+ [![license](https://img.shields.io/npm/l/stroid)](./LICENSE)
7
+ [![CI](https://img.shields.io/github/actions/workflow/status/Himesh-Bhattarai/stroid/ci.yml)](https://github.com/Himesh-Bhattarai/stroid/actions)
35
8
 
36
- ## Install
37
-
38
- ```bash
39
- npm install stroid
40
- ```
9
+ **Named-store state engine for TypeScript and React.**
10
+ Every store has a name. Write to it from anywhere — hooks, utilities, server, tests. Optional layers add persistence, sync, async fetch, SSR isolation, and devtools without touching your core logic.
41
11
 
42
- ## Minimal Usage
12
+ > 🚀 **Power in 4 lines:** Create a store, read/write it, optionally persist, sync, or hydrate for SSR.
43
13
 
44
- ```ts
45
- import { createStore, getStore, setStore } from "stroid";
46
-
47
- createStore("counter", { count: 0 });
48
- setStore("counter", "count", 1);
49
-
50
- console.log(getStore("counter"));
14
+ ```tsx
15
+ createStore("user", { name: "Ava", role: "admin" }) // define once
16
+ setStore("user", "name", "Kai") // write from anywhere
17
+ const name = useStore("user", s => s.name) // React hook
51
18
  ```
52
19
 
53
- ## Module Imports
20
+ ---
54
21
 
55
- Core (root) entry:
22
+ ## Layers
56
23
 
57
- ```ts
58
- import { createStore, setStore, getStore } from "stroid";
24
+ ```
25
+ ┌─────────────────────────────────────────────────────────┐
26
+ │ your app │
27
+ ├─────────────────────────────────────────────────────────┤
28
+ │ useStore useSelector useAsyncStore useFormStore │ stroid/react
29
+ ├─────────────────────────────────────────────────────────┤
30
+ │ createStore setStore getStore setStoreBatch │ stroid ← core
31
+ │ createComputed createSelector createEntityStore │
32
+ ├──────────────┬──────────────┬───────────────────────────┤
33
+ │ stroid/persist│ stroid/sync │ stroid/async │ opt-in features
34
+ │ localStorage │ BroadcastCh │ fetch + cache + retry │
35
+ ├──────────────┴──────────────┴───────────────────────────┤
36
+ │ stroid/server createStoreForRequest (AsyncLocalStorage)│ SSR
37
+ ├─────────────────────────────────────────────────────────┤
38
+ │ stroid/devtools stroid/testing stroid/runtime-tools │ tooling
39
+ └─────────────────────────────────────────────────────────┘
59
40
  ```
60
41
 
61
- Subpath modules:
42
+ Each row is independent. Use only what you need.
43
+
44
+ Note: `stroid/core` exports only `createStore`, `setStore`, `getStore`, and `deleteStore`. Import from `stroid` for the full core runtime (batching, reset, hydration, and hooks).
62
45
 
63
- ```ts
64
- import { useStore } from "stroid/react";
65
- import { fetchStore } from "stroid/async";
66
- import { createSelector } from "stroid/selectors";
67
- import { createComputed } from "stroid/computed";
68
- import { createEntityStore } from "stroid/helpers";
69
- import { createMockStore } from "stroid/testing";
70
- import { listStores } from "stroid/runtime-tools";
71
- import { clearAllStores } from "stroid/runtime-admin";
72
- import { createStoreForRequest } from "stroid/server";
73
- ```
46
+ ---
74
47
 
75
- Feature registration (side-effect imports):
48
+ ## Install
76
49
 
77
- ```ts
78
- import "stroid/persist";
79
- import "stroid/sync";
80
- import "stroid/devtools";
50
+ ```bash
51
+ npm install stroid
81
52
  ```
82
53
 
83
- ## Stroid At a Glance
84
-
85
- Core API:
86
- - createStore, createStoreStrict, setStore, setStoreBatch, getStore, deleteStore, resetStore, hasStore, hydrateStores
87
- - store(name) and namespace(ns) helpers for typed handles
88
- - createComputed, invalidateComputed, deleteComputed, isComputedStore
89
- - configureStroid and queryIntegrations helpers
90
-
91
- Runtime layers:
92
- - stroid/react: useStore, useStoreField, useSelector, useStoreStatic, useAsyncStore, useFormStore, useAsyncStoreSuspense
93
- - stroid/async: fetchStore, refetchStore, enableRevalidateOnFocus, getAsyncMetrics
94
- - stroid/selectors: createSelector, subscribeWithSelector
95
-
96
- Store-attached features (side-effect imports):
97
- - stroid/persist
98
- - stroid/sync
99
- - stroid/devtools
100
-
101
- Operational tools:
102
- - stroid/runtime-tools
103
- - stroid/runtime-admin
104
- - stroid/server
105
- - stroid/helpers
106
- - stroid/testing
107
- - stroid/computed
108
-
109
- ## Public API Index
110
-
111
- Root export names (stroid and stroid/core):
112
- - `createStore(name, initialState, options?)`
113
- - `createStoreStrict(name, initialState, options?)`
114
- - `setStore(nameOrHandle, updateOrPath, value?)`
115
- - `setStoreBatch(fn)`
116
- - `getStore(nameOrHandle, path?)`
117
- - `deleteStore(nameOrHandle)`
118
- - `resetStore(nameOrHandle)`
119
- - `hasStore(nameOrHandle)`
120
- - `hydrateStores(snapshot, options?, trustOptions?)`
121
- - `store(name)`
122
- - `namespace(ns)`
123
- - `createComputed(name, deps, compute, options?)`
124
- - `invalidateComputed(name)`
125
- - `deleteComputed(name)`
126
- - `isComputedStore(name)`
127
- - `configureStroid(config)`
128
- - `queryIntegrations (reactQueryKey, createReactQueryFetcher, swrKey, createSwrFetcher)`
129
-
130
- Root exported types:
131
- - `Path`
132
- - `PathValue`
133
- - `PartialDeep`
134
- - `StoreDefinition`
135
- - `StoreValue`
136
- - `StoreKey`
137
- - `StoreName`
138
- - `StateFor`
139
- - `StoreStateMap`
140
- - `StrictStoreMap`
141
- - `WriteResult`
142
- - `PersistOptions`
143
- - `StoreOptions`
144
- - `SyncOptions`
145
-
146
- ## Subpath API Index
147
-
148
- ### stroid/react
149
-
150
- - `useStore`
151
- - `useStoreField`
152
- - `useSelector`
153
- - `useStoreStatic`
154
- - `useAsyncStore`
155
- - `useFormStore`
156
- - `useAsyncStoreSuspense`
157
-
158
- ### stroid/async
159
-
160
- - `fetchStore`
161
- - `refetchStore`
162
- - `enableRevalidateOnFocus`
163
- - `getAsyncMetrics`
164
- - `_resetAsyncStateForTests`
165
- - `FetchOptions (type)`
166
- - `FetchInput (type)`
167
- - `AsyncStateSnapshot (type)`
168
- - `AsyncStateAdapter (type)`
169
-
170
- ### stroid/selectors
171
-
172
- - `createSelector`
173
- - `subscribeWithSelector`
174
-
175
- ### stroid/computed
176
-
177
- - `createComputed`
178
- - `invalidateComputed`
179
- - `deleteComputed`
180
- - `isComputedStore`
181
- - `_resetComputedForTests`
182
- - `getFullComputedGraph`
183
- - `getComputedDepsFor`
184
-
185
- ### stroid/helpers
186
-
187
- - `createCounterStore`
188
- - `createListStore`
189
- - `createEntityStore`
190
-
191
- ### stroid/testing
192
-
193
- - `createMockStore`
194
- - `withMockedTime`
195
- - `resetAllStoresForTest`
196
- - `benchmarkStoreSet`
197
-
198
- ### stroid/runtime-tools
199
-
200
- - `listStores`
201
- - `getStoreMeta`
202
- - `getInitialState`
203
- - `getMetrics`
204
- - `getSubscriberCount`
205
- - `getAsyncInflightCount`
206
- - `getPersistQueueDepth`
207
- - `getComputedGraph`
208
- - `getComputedDeps`
209
-
210
- ### stroid/runtime-admin
211
-
212
- - `clearAllStores`
213
- - `clearStores`
214
-
215
- ### stroid/server
216
-
217
- - `createStoreForRequest`
218
-
219
- ### stroid/persist
54
+ > **Note:** `main` is locked between releases. Active development is on the `dev` branch — PRs and forks should target `dev`. Commit messages follow [STATUS.md](./STATUS.md) conventions.
220
55
 
221
- - `side-effect only (registers persistence feature)`
56
+ ---
222
57
 
223
- ### stroid/sync
58
+ ## Quick API Reference
224
59
 
225
- - `side-effect only (registers sync feature)`
60
+ | API | Purpose |
61
+ |-----|---------|
62
+ | `createStore(name, state, options?)` | Define a store |
63
+ | `setStore(name, path, value)` | Write a value by path |
64
+ | `setStore(name, draft => { })` | Mutate with a function |
65
+ | `replaceStore(name, value)` | Replace an entire store |
66
+ | `getStore(name, path?)` | Read a store (or a path inside it) |
67
+ | `setStoreBatch(fn)` | Atomic multi-store write, rollback on error |
68
+ | `useStore(name, selector?)` | React hook — subscribes to a store |
69
+ | `useSelector(name, fn)` | React hook — fine-grained derived value |
70
+ | `fetchStore(name, url, options?)` | Async fetch wired to store state |
71
+ | `createComputed(name, deps, fn)` | Reactive derived store |
72
+ | `createStoreForRequest(fn)` | Per-request SSR registry |
73
+ | `hydrateStores(snapshot)` | Rehydrate on client from server state |
226
74
 
227
- ### stroid/devtools
75
+ ---
228
76
 
229
- - `side-effect only (registers devtools feature)`
77
+ ## Quick Start
230
78
 
231
- ## Behavior Notes
79
+ Three levels. Start where you are.
232
80
 
233
- - Feature layers are explicit: persist, sync, and devtools require side-effect imports.
234
- - Default store scope is request; global stores must be opted in.
235
- - Snapshot mode defaults to deep cloning for subscriptions and selector snapshots.
236
- - hydrateStores requires trust options; use allowUntrusted or validate for SSR data.
237
- - fetchStore writes the AsyncStateSnapshot shape by default unless stateAdapter is provided.
238
- - Auto-create for fetchStore is controlled by FetchOptions.autoCreate or global config.
239
- - Persist defaults to localStorage when enabled in the browser.
240
- - Sync uses BroadcastChannel and warns if unavailable.
241
- - Computed deps can be store names or handles; missing deps yield null until created.
242
- - Store option validate replaces legacy schema and validator options.
81
+ ---
243
82
 
244
- ## Short Recipes
83
+ ### Level 1 — The Basics
245
84
 
246
- ### Create and update a store
85
+ **Create a store. Read it. Write to it.**
247
86
 
248
87
  ```ts
249
- import { createStore, setStore, getStore } from "stroid";
88
+ import { createStore, getStore, setStore } from "stroid"
250
89
 
251
- createStore("profile", { name: "Ava", age: 30 });
252
- setStore("profile", "age", 31);
90
+ createStore("counter", { count: 0 })
253
91
 
254
- console.log(getStore("profile"));
92
+ setStore("counter", "count", 1)
93
+ console.log(getStore("counter")) // { count: 1 }
255
94
  ```
256
95
 
257
- ### Use a typed store handle
96
+ **Use it in React.**
258
97
 
259
- ```ts
260
- import { createStore, store, setStore, getStore } from "stroid";
98
+ ```tsx
99
+ import { useStore } from "stroid/react"
261
100
 
262
- const counter = store<"counter", { count: number }>("counter");
263
- createStore("counter", { count: 0 });
264
- setStore(counter, (draft) => { draft.count += 1; });
265
-
266
- console.log(getStore(counter, "count"));
101
+ function Counter() {
102
+ const count = useStore("counter", s => s.count)
103
+ return (
104
+ <button onClick={() => setStore("counter", "count", count + 1)}>
105
+ {count}
106
+ </button>
107
+ )
108
+ }
267
109
  ```
268
110
 
269
- ### Batch multiple writes
111
+ **Batch multiple writes — one notification, atomic rollback.**
270
112
 
271
113
  ```ts
272
- import { setStoreBatch, setStore } from "stroid";
114
+ import { setStoreBatch, setStore } from "stroid"
273
115
 
274
116
  setStoreBatch(() => {
275
- setStore("a", { value: 1 });
276
- setStore("b", { value: 2 });
277
- });
117
+ setStore("cart", { items: [{ id: 1, price: 12 }] })
118
+ setStore("ui", "loading", false)
119
+ setStore("user", "lastSeen", Date.now())
120
+ // if any write throws → all three roll back
121
+ })
278
122
  ```
279
123
 
280
- ### Path updates with strict keys
124
+ **Typed store handle trade string keys for compile-time safety.**
281
125
 
282
126
  ```ts
283
- import { createStore, setStore } from "stroid";
284
-
285
- createStore("user", { profile: { name: "Ava" } });
286
- setStore("user", "profile.name", "Kai");
287
- ```
127
+ import { store, createStore, setStore, getStore } from "stroid"
288
128
 
289
- ### Path updates with pathCreate
129
+ const counter = store<"counter", { count: number }>("counter")
290
130
 
291
- ```ts
292
- import { createStore, setStore } from "stroid";
293
-
294
- createStore("user", { profile: { name: "Ava" } }, { pathCreate: true });
295
- setStore("user", "profile.age", 32);
131
+ createStore("counter", { count: 0 })
132
+ setStore(counter, draft => { draft.count += 1 })
133
+ console.log(getStore(counter, "count")) // 1
296
134
  ```
297
135
 
298
- ### React hooks
136
+ **Type-safe string store names (module augmentation).**
299
137
 
300
- ```ts
301
- import { useStore } from "stroid/react";
138
+ If you prefer `useStore("user")` and `setStore("user", ...)` with compile-time checking,
139
+ augment `StoreStateMap` or `StrictStoreMap` in a `.d.ts` file:
302
140
 
303
- function Counter() {
304
- const state = useStore("counter");
305
- return <div>{state?.count ?? 0}</div>;
141
+ ```ts
142
+ // src/stroid.d.ts
143
+ declare module "stroid" {
144
+ interface StoreStateMap {
145
+ user: {
146
+ name: string
147
+ role: "admin" | "user"
148
+ }
149
+ }
306
150
  }
151
+
152
+ // Optional strict opt-in for locked store names:
153
+ // declare module "stroid" { interface StrictStoreMap { user: ... } }
154
+ // If you import from "stroid/core", add the same module augmentation there.
307
155
  ```
308
156
 
309
- ### Selectors
310
157
 
311
- ```ts
312
- import { createSelector } from "stroid/selectors";
158
+ ---
313
159
 
314
- const selectName = createSelector("profile", (state) => state.name);
315
- console.log(selectName());
316
- ```
160
+ ### Level 2 Real Features
317
161
 
318
- ### Computed stores
162
+ **Persist to localStorage — survives page reload.**
319
163
 
320
- ```ts
321
- import { createComputed } from "stroid/computed";
164
+ > ⚡ **Tip:** Add `import "stroid/persist"` once at your app entry (e.g. `main.tsx`) to enable persistence globally. Any store with a `persist` option will activate automatically.
322
165
 
323
- createComputed("total", ["cart"], (cart) => {
324
- return cart ? cart.items.reduce((sum, item) => sum + item.price, 0) : 0;
325
- });
166
+ ```ts
167
+ import { createStore } from "stroid"
168
+ import "stroid/persist"
169
+
170
+ createStore("settings", { theme: "dark", lang: "en" }, {
171
+ persist: {
172
+ key: "app-settings",
173
+ allowPlaintext: true,
174
+ version: 2,
175
+ migrate: (old, v) => v === 1 ? { ...old, lang: "en" } : old,
176
+ }
177
+ })
326
178
  ```
327
179
 
328
- ### Persisted store
180
+ **Sync across browser tabs — zero wiring.**
329
181
 
330
- ```ts
331
- import { createStore } from "stroid";
332
- import "stroid/persist";
182
+ > ⚡ **Tip:** Add `import "stroid/sync"` once at app entry. Any store with `sync: true` or `sync: { channel }` will start broadcasting automatically.
333
183
 
334
- createStore("prefs", { theme: "dark" }, {
335
- persist: { key: "prefs", allowPlaintext: true },
336
- });
184
+ ```ts
185
+ import { createStore } from "stroid"
186
+ import "stroid/sync"
187
+
188
+ createStore("presence", { online: true, cursor: null }, {
189
+ sync: { channel: "presence-sync" }
190
+ // Lamport clock conflict resolution built in.
191
+ // Stale messages from closed tabs auto-rejected.
192
+ })
337
193
  ```
338
194
 
339
- ### Sync across tabs
195
+ **Persist + sync together.**
340
196
 
341
197
  ```ts
342
- import { createStore } from "stroid";
343
- import "stroid/sync";
344
-
345
- createStore("shared", { value: 0 }, { sync: true });
198
+ import { createStore } from "stroid"
199
+ import "stroid/persist"
200
+ import "stroid/sync"
201
+
202
+ createStore("settings", { theme: "dark", lang: "en" }, {
203
+ persist: { key: "app-settings", allowPlaintext: true },
204
+ sync: { channel: "settings-sync" },
205
+ })
206
+ // Change in one tab → persisted locally + broadcast to all other tabs.
346
207
  ```
347
208
 
348
- ### Async fetch store
209
+ **Async fetch — SWR-style, wired directly to store state.**
210
+
211
+ > ⚡ **Tip:** `fetchStore` manages `loading`, `error`, `data`, and `status` fields automatically. No separate state machine needed — just read `useStore("user")`.
349
212
 
350
213
  ```ts
351
- import { createStore } from "stroid";
352
- import { fetchStore } from "stroid/async";
214
+ import { createStore } from "stroid"
215
+ import { fetchStore } from "stroid/async"
216
+ import { useStore } from "stroid/react"
353
217
 
354
- createStore("user", { data: null, loading: false, error: null, status: "idle" });
355
- fetchStore("user", "/api/user");
356
- ```
218
+ createStore("user", { data: null, loading: false, error: null, status: "idle" })
357
219
 
358
- ### Async fetch with adapter
359
-
360
- ```ts
361
- import { fetchStore } from "stroid/async";
220
+ const controller = new AbortController()
362
221
 
363
222
  fetchStore("user", "/api/user", {
364
- stateAdapter: ({ next, set }) => set({ user: next.data, status: next.status }),
365
- });
223
+ signal: controller.signal,
224
+ ttl: 30_000, // 30s cache
225
+ staleWhileRevalidate: true, // show stale, revalidate in background
226
+ dedupe: true, // concurrent calls share one request
227
+ retry: 3, // auto-retry on failure
228
+ retryDelay: 400,
229
+ transform: res => res.data, // shape the response
230
+ onSuccess: data => console.log("fetched", data),
231
+ onError: err => Sentry.captureException(err),
232
+ })
233
+
234
+ function UserCard() {
235
+ const user = useStore("user")
236
+ if (user?.loading) return <Spinner />
237
+ if (user?.error) return <Error message={user.error} />
238
+ return <div>{user?.data?.name}</div>
239
+ }
366
240
  ```
367
241
 
368
- ### SSR request scope
242
+ **Computed stores reactive, cached, cycle-safe.**
369
243
 
370
244
  ```ts
371
- import { createStoreForRequest } from "stroid/server";
372
-
373
- const requestStore = createStoreForRequest(({ create, set }) => {
374
- create("session", { id: null });
375
- set("session", (draft) => { draft.id = "abc"; });
376
- });
377
-
378
- requestStore.hydrate(() => renderApp());
245
+ import { createStore } from "stroid"
246
+ import { createComputed } from "stroid/computed"
247
+
248
+ createStore("cart", { items: [] })
249
+ createStore("discount", { pct: 10 })
250
+
251
+ createComputed(
252
+ "cartTotal",
253
+ ["cart", "discount"],
254
+ (cart, discount) => {
255
+ const raw = cart.items.reduce((sum, i) => sum + i.price, 0)
256
+ return raw * (1 - discount.pct / 100)
257
+ }
258
+ )
259
+
260
+ // cartTotal updates whenever cart or discount changes.
261
+ // Circular dependency detected at definition time.
262
+ // Flush order is topologically sorted — always correct.
379
263
  ```
380
264
 
381
- ### Helpers
265
+ **Entity store — built-in CRUD for collections.**
382
266
 
383
267
  ```ts
384
- import { createEntityStore } from "stroid/helpers";
268
+ import { createEntityStore } from "stroid/helpers"
385
269
 
386
- const users = createEntityStore("users");
387
- users.upsert({ id: "1", name: "Ava" });
388
- console.log(users.get("1"));
389
- ```
270
+ const users = createEntityStore("users")
390
271
 
391
- ### Runtime inspection
272
+ users.upsert({ id: "1", name: "Ava", role: "admin" })
273
+ users.upsert({ id: "2", name: "Kai", role: "user" })
392
274
 
393
- ```ts
394
- import { listStores, getMetrics } from "stroid/runtime-tools";
275
+ console.log(users.get("1")) // { id: "1", name: "Ava", role: "admin" }
276
+ console.log(users.getAll()) // [{ id: "1" }, { id: "2" }]
395
277
 
396
- const names = listStores();
397
- const metrics = getMetrics(names[0]);
398
- console.log(metrics);
278
+ users.remove("2")
399
279
  ```
400
280
 
401
- ### Runtime cleanup
281
+ ---
402
282
 
403
- ```ts
404
- import { clearAllStores } from "stroid/runtime-admin";
405
-
406
- clearAllStores();
407
- ```
283
+ ### Level 3 — Production Patterns
408
284
 
409
- ### React Query integration
285
+ **SSR with per-request isolation — no cross-request leaks.**
410
286
 
411
287
  ```ts
412
- import { queryIntegrations } from "stroid";
288
+ // app/api/render/route.ts (Next.js App Router)
289
+ import { createStoreForRequest } from "stroid/server"
290
+ import { renderToString } from "react-dom/server"
291
+
292
+ export async function GET(req: Request) {
293
+ const session = await getSession(req)
294
+
295
+ // Each request gets a fully isolated registry.
296
+ // AsyncLocalStorage ensures concurrent requests
297
+ // never share store values or subscribers.
298
+ const stores = createStoreForRequest((api) => {
299
+ api.create("user", { name: session.user.name, role: session.user.role })
300
+ api.create("cart", { items: [] })
301
+ api.create("flags", session.featureFlags)
302
+ })
303
+
304
+ const html = stores.hydrate(() => renderToString(<App />))
305
+ const state = stores.snapshot() // plain JSON → send to client
306
+
307
+ return Response.json({ html, state })
308
+ }
413
309
 
414
- const key = queryIntegrations.reactQueryKey("user", 1);
415
- const fetcher = queryIntegrations.createReactQueryFetcher("user", "/api/user");
310
+ // Client: rehydrate from server snapshot
311
+ hydrateStores(window.__STROID_STATE__)
416
312
 
417
- console.log(key, fetcher);
313
+ Tip: For typed SSR APIs, either augment `StoreStateMap` or pass a generic:
314
+ `createStoreForRequest<{ user: UserState }>((api) => { ... })`.
418
315
  ```
419
316
 
420
- ## Docs
421
-
422
- Quick links:
423
- - [Book Contents](docs/FRONT_MATTER/CONTENTS.md)
424
- - [Start Here](docs/BODY_MATTER/BEGINNER_GUIDE/START_HERE.md)
425
- - [Install and Imports](docs/BODY_MATTER/BEGINNER_GUIDE/INSTALL_AND_IMPORTS.md)
426
- - [Core of Stroid](docs/BODY_MATTER/CORE_OF_STROID/INTRODUCTION.md)
427
- - [React Layer](docs/BODY_MATTER/REACT_OF_STROID/INTRODUCTION.md)
428
- - [Async Layer](docs/BODY_MATTER/ASYNC_OF_STROID/INTRODUCTION.md)
429
- - [Persistence](docs/BODY_MATTER/PERSIST_OF_STROID/INTRODUCTION.md)
430
- - [Sync](docs/BODY_MATTER/SYNC_OF_STROID/INTRODUCTION.md)
431
- - [Runtime Operations](docs/BODY_MATTER/RUNTIME_OPERATIONS_OF_STROID/INTRODUCTION.md)
432
- - [Server and SSR](docs/BODY_MATTER/SERVER_OF_STROID/INTRODUCTION.md)
433
- - [Helpers](docs/BODY_MATTER/HELPERS_AND_CHAIN_OF_STROID/INTRODUCTION.md)
434
- - [Testing](docs/BODY_MATTER/TESTING_OF_STROID/INTRODUCTION.md)
435
- - [Selectors](docs/BODY_MATTER/SELECTORS_OF_STROID/INTRODUCTION.md)
436
- - [Devtools](docs/BODY_MATTER/DEVTOOLS_OF_STROID/INTRODUCTION.md)
437
-
438
- ## Docs Index (Full)
439
-
440
- ### Architecture
441
-
442
- - [Architecture](docs/ARCHITECTURE/ARCHITECTURE.md)
317
+ **Middleware — intercept, transform, or veto any write.**
443
318
 
444
- ### Back Matter
445
-
446
- - [Appendices](docs/BACK_MATTER/APPENDICES.md)
447
- - [Back Cover](docs/BACK_MATTER/BACK_COVER.md)
448
- - [Bibliography](docs/BACK_MATTER/Bibliography.md)
449
- - [Colophon](docs/BACK_MATTER/Colophon.md)
450
- - [Contact Information](docs/BACK_MATTER/Contact_Information.md)
319
+ ```ts
320
+ createStore("cart", { items: [], total: 0 }, {
321
+ middleware: (ctx) => {
322
+ // ctx.action = "set" | "reset" | "hydrate"
323
+ // ctx.prev = previous state
324
+ // ctx.next = incoming state
325
+ // return MIDDLEWARE_ABORT to cancel the write
326
+ if (ctx.action === "set" && ctx.next.items.length > 100) {
327
+ ctx.options.onError?.("Cart limit exceeded")
328
+ return MIDDLEWARE_ABORT
329
+ }
330
+ // log every write to your analytics
331
+ analytics.track("cart.updated", { prev: ctx.prev, next: ctx.next })
332
+ return ctx.next
333
+ }
334
+ })
335
+ ```
451
336
 
452
- ### Body Matter
337
+ **Persist with encryption — no plaintext secrets in localStorage.**
453
338
 
454
- - [Back Cover](docs/BODY_MATTER/BACK_COVER.md)
339
+ ```ts
340
+ import { createStore } from "stroid"
341
+ import "stroid/persist"
342
+
343
+ createStore("vault", { apiKey: "", token: "" }, {
344
+ persist: {
345
+ key: "secure-vault",
346
+ encrypt: (data) => myAES.encrypt(JSON.stringify(data)),
347
+ decrypt: (raw) => JSON.parse(myAES.decrypt(raw)),
348
+ // sensitiveData: true blocks persist entirely if no encrypt is provided
349
+ sensitiveData: true,
350
+ onStorageCleared: ({ name, reason }) => {
351
+ // fires when localStorage is cleared externally (another tab, devtools, etc.)
352
+ console.warn(`${name} storage cleared: ${reason}`)
353
+ redirectToLogin()
354
+ },
355
+ }
356
+ })
357
+ ```
455
358
 
456
- ### Body Matter - Async Of Stroid
359
+ **Observability inspect any store at runtime.**
457
360
 
458
- - [Cache And Revalidation](docs/BODY_MATTER/ASYNC_OF_STROID/CACHE_AND_REVALIDATION.md)
459
- - [Fetch Flow](docs/BODY_MATTER/ASYNC_OF_STROID/FETCH_FLOW.md)
460
- - [Introduction](docs/BODY_MATTER/ASYNC_OF_STROID/INTRODUCTION.md)
461
- - [Real Use](docs/BODY_MATTER/ASYNC_OF_STROID/REAL_USE.md)
361
+ > ⚡ **Tip:** Add `import "stroid/devtools"` at app entry to enable time-travel history and store inspection. Use `getMetrics(name)` in production to track notification performance per store.
462
362
 
463
- ### Body Matter - Beginner Guide
363
+ ```ts
364
+ import { getMetrics, getSubscriberCount, getComputedGraph } from "stroid/runtime-tools"
464
365
 
465
- - [First Store](docs/BODY_MATTER/BEGINNER_GUIDE/FIRST_STORE.md)
466
- - [From Basic To Real](docs/BODY_MATTER/BEGINNER_GUIDE/FROM_BASIC_TO_REAL.md)
467
- - [Install And Imports](docs/BODY_MATTER/BEGINNER_GUIDE/INSTALL_AND_IMPORTS.md)
468
- - [React Usage](docs/BODY_MATTER/BEGINNER_GUIDE/REACT_USAGE.md)
469
- - [Start Here](docs/BODY_MATTER/BEGINNER_GUIDE/START_HERE.md)
366
+ // Per-store performance metrics
367
+ const m = getMetrics("cart")
368
+ // { notifyCount: 42, totalNotifyMs: 8.3, lastNotifyMs: 0.2 }
470
369
 
471
- ### Body Matter - Binary To Being
370
+ // How many components are subscribed right now
371
+ console.log(getSubscriberCount("cart")) // 3
472
372
 
473
- - [Async Layer](docs/BODY_MATTER/BINARY_TO_BEING/ASYNC_LAYER.md)
474
- - [Design Principles Of Stroid](docs/BODY_MATTER/BINARY_TO_BEING/DESIGN_PRINCIPLES_OF_STROID.md)
475
- - [Persistence Layer](docs/BODY_MATTER/BINARY_TO_BEING/PERSISTENCE_LAYER.md)
476
- - [Production Patterns](docs/BODY_MATTER/BINARY_TO_BEING/PRODUCTION_PATTERNS.md)
477
- - [React Bindings](docs/BODY_MATTER/BINARY_TO_BEING/REACT_BINDINGS.md)
478
- - [Runtime Architecture](docs/BODY_MATTER/BINARY_TO_BEING/RUNTIME_ARCHITECTURE.md)
479
- - [Selectors](docs/BODY_MATTER/BINARY_TO_BEING/SELECTORS.md)
480
- - [Store System](docs/BODY_MATTER/BINARY_TO_BEING/STORE_SYSTEM.md)
481
- - [Tooling And Debugging](docs/BODY_MATTER/BINARY_TO_BEING/TOOLING_AND_DEBUGGING.md)
482
- - [Why State Management Fails In Large Apps](docs/BODY_MATTER/BINARY_TO_BEING/WHY_STATE_MANAGEMENT_FAILS_IN_LARGE_APPS.md)
373
+ // Full computed dependency graph
374
+ console.log(getComputedGraph())
375
+ // { nodes: ["cartTotal"], edges: [{ from: "cart", to: "cartTotal" }] }
376
+ ```
483
377
 
484
- ### Body Matter - Bug As Helper
378
+ **Global flush configuration tune for your app's load profile.**
485
379
 
486
- - [Intentional Bugs](docs/BODY_MATTER/BUG_AS_HELPER/INTENTIONAL_BUGS.md)
487
- - [Introduction](docs/BODY_MATTER/BUG_AS_HELPER/INTRODUCTION.md)
488
- - [No Need To Fix](docs/BODY_MATTER/BUG_AS_HELPER/NO_NEED_TO_FIX.md)
489
- - [Real Use](docs/BODY_MATTER/BUG_AS_HELPER/REAL_USE.md)
380
+ ```ts
381
+ import { configureStroid } from "stroid"
382
+
383
+ configureStroid({
384
+ // Route internal logs to your observability platform
385
+ logSink: {
386
+ warn: msg => Sentry.captureMessage(msg, "warning"),
387
+ critical: msg => Sentry.captureException(new Error(msg)),
388
+ },
389
+
390
+ // Priority stores notify subscribers first
391
+ flush: {
392
+ priorityStores: ["auth", "user"],
393
+ },
394
+
395
+ // Revalidate async stores when tab regains focus
396
+ revalidateOnFocus: {
397
+ debounceMs: 500,
398
+ maxConcurrent: 3,
399
+ staggerMs: 100,
400
+ },
401
+ })
402
+ ```
490
403
 
491
- ### Body Matter - Core Of Stroid
404
+ **Large store performance (recommendations).**
492
405
 
493
- - [Core Options](docs/BODY_MATTER/CORE_OF_STROID/CORE_OPTIONS.md)
494
- - [Example](docs/BODY_MATTER/CORE_OF_STROID/EXAMPLE.md)
495
- - [Introduction](docs/BODY_MATTER/CORE_OF_STROID/INTRODUCTION.md)
496
- - [Real Use](docs/BODY_MATTER/CORE_OF_STROID/REAL_USE.md)
406
+ - Split stores by domain to keep hot updates small.
407
+ - For large lists, prefer `snapshot: "shallow"` per store or `configureStroid({ snapshotStrategy: "shallow" })` globally.
408
+ - Prefer path updates and targeted selectors (`useSelector`, `useStoreField`) over whole-store subscriptions.
497
409
 
498
- ### Body Matter - Devtools Of Stroid
410
+ **Optional structural sharing for mutator updates.**
499
411
 
500
- - [History And Redaction](docs/BODY_MATTER/DEVTOOLS_OF_STROID/HISTORY_AND_REDACTION.md)
501
- - [Introduction](docs/BODY_MATTER/DEVTOOLS_OF_STROID/INTRODUCTION.md)
502
- - [Real Use](docs/BODY_MATTER/DEVTOOLS_OF_STROID/REAL_USE.md)
503
- - [Redux Devtools And Boundaries](docs/BODY_MATTER/DEVTOOLS_OF_STROID/REDUX_DEVTOOLS_AND_BOUNDARIES.md)
412
+ ```ts
413
+ import { configureStroid } from "stroid"
414
+ import { produce } from "immer"
504
415
 
505
- ### Body Matter - Helpers And Chain Of Stroid
416
+ configureStroid({ mutatorProduce: produce })
417
+ ```
506
418
 
507
- - [Chain Api](docs/BODY_MATTER/HELPERS_AND_CHAIN_OF_STROID/CHAIN_API.md)
508
- - [Helper Factories](docs/BODY_MATTER/HELPERS_AND_CHAIN_OF_STROID/HELPER_FACTORIES.md)
509
- - [Introduction](docs/BODY_MATTER/HELPERS_AND_CHAIN_OF_STROID/INTRODUCTION.md)
510
- - [Real Use](docs/BODY_MATTER/HELPERS_AND_CHAIN_OF_STROID/REAL_USE.md)
419
+ If you prefer a shorthand, set `globalThis.__STROID_IMMER_PRODUCE__ = produce` once and use `configureStroid({ mutatorProduce: "immer" })`.
511
420
 
512
- ### Body Matter - Opt In Features Of Stroid
421
+ **Testing deterministic, isolated, zero globals.**
513
422
 
514
- - [Introduction](docs/BODY_MATTER/OPT_IN_FEATURES_OF_STROID/INTRODUCTION.md)
515
- - [Power Tools](docs/BODY_MATTER/OPT_IN_FEATURES_OF_STROID/POWER_TOOLS.md)
516
- - [Runtime Layers](docs/BODY_MATTER/OPT_IN_FEATURES_OF_STROID/RUNTIME_LAYERS.md)
517
- - [Store Features](docs/BODY_MATTER/OPT_IN_FEATURES_OF_STROID/STORE_FEATURES.md)
423
+ ```ts
424
+ import { createMockStore, resetAllStoresForTest } from "stroid/testing"
518
425
 
519
- ### Body Matter - Persist Of Stroid
426
+ beforeEach(() => resetAllStoresForTest())
520
427
 
521
- - [Failure And Recovery](docs/BODY_MATTER/PERSIST_OF_STROID/FAILURE_AND_RECOVERY.md)
522
- - [Introduction](docs/BODY_MATTER/PERSIST_OF_STROID/INTRODUCTION.md)
523
- - [Real Use](docs/BODY_MATTER/PERSIST_OF_STROID/REAL_USE.md)
524
- - [Storage And Migrations](docs/BODY_MATTER/PERSIST_OF_STROID/STORAGE_AND_MIGRATIONS.md)
428
+ test("cart total updates when item added", () => {
429
+ const cart = createMockStore("cart", { items: [] })
525
430
 
526
- ### Body Matter - Philosophy Of Stroid
431
+ setStore("cart", "items", [{ id: 1, price: 50 }])
527
432
 
528
- - [Minimal Abstraction](docs/BODY_MATTER/PHILOSOPHY_OF_STROID/MINIMAL_ABSTRACTION.md)
529
- - [Optional Complexity And Comparison](docs/BODY_MATTER/PHILOSOPHY_OF_STROID/OPTIONAL_COMPLEXITY_AND_COMPARISON.md)
530
- - [Predictable State Mutation](docs/BODY_MATTER/PHILOSOPHY_OF_STROID/PREDICTABLE_STATE_MUTATION.md)
531
- - [Runtime Observability](docs/BODY_MATTER/PHILOSOPHY_OF_STROID/RUNTIME_OBSERVABILITY.md)
532
- - [Why The Mind Needs Structure](docs/BODY_MATTER/PHILOSOPHY_OF_STROID/WHY_THE_MIND_NEEDS_STRUCTURE.md)
433
+ expect(getStore("cart", "items")).toHaveLength(1)
434
+ expect(getStore("cartTotal")).toBe(45) // with 10% discount
435
+ })
436
+ ```
533
437
 
534
- ### Body Matter - React Of Stroid
438
+ ---
535
439
 
536
- - [Form And Async](docs/BODY_MATTER/REACT_OF_STROID/FORM_AND_ASYNC.md)
537
- - [Hooks](docs/BODY_MATTER/REACT_OF_STROID/HOOKS.md)
538
- - [Introduction](docs/BODY_MATTER/REACT_OF_STROID/INTRODUCTION.md)
539
- - [Real Use](docs/BODY_MATTER/REACT_OF_STROID/REAL_USE.md)
440
+ ## Module Imports
540
441
 
541
- ### Body Matter - Roadmap Of Stroid
442
+ ```ts
443
+ // Core
444
+ import { createStore, setStore, getStore, deleteStore,
445
+ resetStore, hasStore, setStoreBatch, hydrateStores } from "stroid"
542
446
 
543
- - [Roadmap](docs/BODY_MATTER/ROADMAP_OF_STROID/ROADMAP.md)
447
+ // React
448
+ import { useStore, useSelector, useStoreField,
449
+ useAsyncStore, useFormStore, useAsyncStoreSuspense } from "stroid/react"
544
450
 
545
- ### Body Matter - Runtime Operations Of Stroid
451
+ // Async
452
+ import { fetchStore, refetchStore, enableRevalidateOnFocus } from "stroid/async"
546
453
 
547
- - [Admin Operations](docs/BODY_MATTER/RUNTIME_OPERATIONS_OF_STROID/ADMIN_OPERATIONS.md)
548
- - [Inspection Tools](docs/BODY_MATTER/RUNTIME_OPERATIONS_OF_STROID/INSPECTION_TOOLS.md)
549
- - [Introduction](docs/BODY_MATTER/RUNTIME_OPERATIONS_OF_STROID/INTRODUCTION.md)
550
- - [Real Use](docs/BODY_MATTER/RUNTIME_OPERATIONS_OF_STROID/REAL_USE.md)
454
+ // Selectors & Computed
455
+ import { createSelector, subscribeWithSelector } from "stroid/selectors"
456
+ import { createComputed, deleteComputed } from "stroid/computed"
551
457
 
552
- ### Body Matter - Selectors Of Stroid
458
+ // Features (side-effect imports register once at app entry)
459
+ import "stroid/persist"
460
+ import "stroid/sync"
461
+ import "stroid/devtools"
553
462
 
554
- - [Create Selector](docs/BODY_MATTER/SELECTORS_OF_STROID/CREATE_SELECTOR.md)
555
- - [Introduction](docs/BODY_MATTER/SELECTORS_OF_STROID/INTRODUCTION.md)
556
- - [Real Use](docs/BODY_MATTER/SELECTORS_OF_STROID/REAL_USE.md)
557
- - [Subscribe With Selector](docs/BODY_MATTER/SELECTORS_OF_STROID/SUBSCRIBE_WITH_SELECTOR.md)
463
+ // Server / SSR
464
+ import { createStoreForRequest } from "stroid/server"
558
465
 
559
- ### Body Matter - Server Of Stroid
466
+ // Helpers & Testing
467
+ import { createEntityStore, createCounterStore } from "stroid/helpers"
468
+ import { createMockStore, resetAllStoresForTest } from "stroid/testing"
560
469
 
561
- - [Hydrate Flow](docs/BODY_MATTER/SERVER_OF_STROID/HYDRATE_FLOW.md)
562
- - [Introduction](docs/BODY_MATTER/SERVER_OF_STROID/INTRODUCTION.md)
563
- - [Real Use](docs/BODY_MATTER/SERVER_OF_STROID/REAL_USE.md)
564
- - [Request Scope](docs/BODY_MATTER/SERVER_OF_STROID/REQUEST_SCOPE.md)
470
+ // Runtime
471
+ import { listStores, getMetrics, getComputedGraph } from "stroid/runtime-tools"
472
+ import { clearAllStores } from "stroid/runtime-admin"
473
+ ```
565
474
 
566
- ### Body Matter - Sync Of Stroid
475
+ ---
567
476
 
568
- - [Conflicts And Recovery](docs/BODY_MATTER/SYNC_OF_STROID/CONFLICTS_AND_RECOVERY.md)
569
- - [Introduction](docs/BODY_MATTER/SYNC_OF_STROID/INTRODUCTION.md)
570
- - [Real Use](docs/BODY_MATTER/SYNC_OF_STROID/REAL_USE.md)
571
- - [Sync Options](docs/BODY_MATTER/SYNC_OF_STROID/SYNC_OPTIONS.md)
477
+ ## Behavior Notes
572
478
 
573
- ### Body Matter - Testing Of Stroid
479
+ - **Features are explicit.** `persist`, `sync`, and `devtools` require a side-effect import. Nothing loads you didn't ask for.
480
+ - **Snapshot mode defaults to deep clone.** Subscribers and selectors always receive immutable snapshots.
481
+ - **`setStoreBatch` is transactional.** All writes stage first. Commit happens only if the batch completes without error. On failure, all writes roll back.
482
+ - **`setStore(name, data)` merges objects.** It shallow-merges into object stores. Use `replaceStore(name, value)` to replace the whole store.
483
+ - **Typed string store names are opt-in.** If you want `setStore("user", "profile.name", ...)` to be checked, augment `StoreStateMap` or use typed store handles.
484
+ - **SSR stores are request-scoped by default.** Global SSR stores require `{ allowSSRGlobalStore: true }`.
485
+ - **`fetchStore` deduplicates by default.** Concurrent calls with the same store name share one in-flight request.
486
+ - **Computed deps can be store names or handles.** Missing deps yield `null` until the dependency store is created.
487
+ - **Persist defaults to `localStorage`.** Provide a custom `driver` for `sessionStorage`, `IndexedDB`, or any storage adapter.
488
+ - **Sync uses `BroadcastChannel`.** Warns and no-ops gracefully when unavailable (Safari private mode, Node).
574
489
 
575
- - [Introduction](docs/BODY_MATTER/TESTING_OF_STROID/INTRODUCTION.md)
576
- - [Mocks And Time](docs/BODY_MATTER/TESTING_OF_STROID/MOCKS_AND_TIME.md)
577
- - [Real Use](docs/BODY_MATTER/TESTING_OF_STROID/REAL_USE.md)
578
- - [Resets And Benchmarks](docs/BODY_MATTER/TESTING_OF_STROID/RESETS_AND_BENCHMARKS.md)
490
+ ---
579
491
 
580
- ### Body Matter - The Glitch In Matrix
492
+ ## Docs
581
493
 
582
- - [Introduction](docs/BODY_MATTER/THE_GLITCH_IN_MATRIX/INTRODUCTION.md)
583
- - [Performance And Reality](docs/BODY_MATTER/THE_GLITCH_IN_MATRIX/PERFORMANCE_AND_REALITY.md)
584
- - [Real Use](docs/BODY_MATTER/THE_GLITCH_IN_MATRIX/REAL_USE.md)
585
- - [Tradeoffs And Limits](docs/BODY_MATTER/THE_GLITCH_IN_MATRIX/TRADEOFFS_AND_LIMITS.md)
494
+ Full documentation, architecture guide, and examples:
586
495
 
587
- ### Front Matter
496
+ - [Start Here](./docs/start-here.md)
497
+ - [Core API](./docs/core.md)
498
+ - [React Layer](./docs/react.md)
499
+ - [Async Layer](./docs/async.md)
500
+ - [Persistence](./docs/persist.md)
501
+ - [Cross-tab Sync](./docs/sync.md)
502
+ - [Server & SSR](./docs/server.md)
503
+ - [Computed Stores](./docs/computed.md)
504
+ - [Selectors](./docs/selectors.md)
505
+ - [Testing](./docs/testing.md)
506
+ - [Devtools](./docs/devtools.md)
507
+ - [Runtime Tools](./docs/runtime.md)
588
508
 
589
- - [About Author](docs/FRONT_MATTER/ABOUT_AUTHOR.md)
590
- - [Acknowledge](docs/FRONT_MATTER/ACKNOWLEDGE.md)
591
- - [Contents](docs/FRONT_MATTER/CONTENTS.md)
592
- - [Copyright](docs/FRONT_MATTER/COPYRIGHT.md)
593
- - [Dedication](docs/FRONT_MATTER/DEDICATION.md)
594
- - [Epigraph](docs/FRONT_MATTER/EPIGRAPH.md)
595
- - [Foreword](docs/FRONT_MATTER/FOREWORD.md)
596
- - [Front Cover Page](docs/FRONT_MATTER/FRONT_COVER_PAGE.md)
597
- - [How To Use](docs/FRONT_MATTER/HOW_TO_USE.md)
598
- - [Introduction](docs/FRONT_MATTER/INTRODUCTION.md)
599
- - [List Of Table](docs/FRONT_MATTER/LIST_OF_TABLE.md)
600
- - [Praise](docs/FRONT_MATTER/PRAISE.md)
601
- - [Preface](docs/FRONT_MATTER/PREFACE.md)
602
- - [Title Page](docs/FRONT_MATTER/TITLE_PAGE.md)
509
+ ---
603
510
 
604
- ## Changelog and License
511
+ ## Changelog & License
605
512
 
606
- - [CHANGELOG](CHANGELOG.md)
607
- - [LICENSE](LICENSE)
513
+ - [CHANGELOG](./CHANGELOG.md)
514
+ - [MIT License](./LICENSE)
608
515
  - [Issues](https://github.com/Himesh-Bhattarai/stroid/issues)