memorio 4.9.31 → 5.0.0

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 (76) hide show
  1. package/AGENTS.md +3 -3
  2. package/README.md +327 -330
  3. package/SECURITY.md +17 -1
  4. package/SUMMARY.md +59 -45
  5. package/adr/001-state-proxy-model.md +96 -0
  6. package/adr/002-observer-semantics.md +180 -0
  7. package/adr/003-deep-mutation-semantics.md +129 -0
  8. package/adr/004-array-mutation-semantics.md +128 -0
  9. package/adr/005-scheduler-contract.md +149 -0
  10. package/adr/006-context-isolation.md +92 -0
  11. package/adr/007-mutation-records.md +118 -0
  12. package/adr/008-transactions.md +106 -0
  13. package/adr/009-history-model.md +110 -0
  14. package/adr/README.md +46 -0
  15. package/adr/template.md +49 -0
  16. package/examples/basic.ts +115 -115
  17. package/examples/browser-vanilla.html +358 -358
  18. package/examples/cache.ts +72 -72
  19. package/examples/cross-platform-guards.ts +57 -57
  20. package/examples/history.ts +104 -0
  21. package/examples/idb.ts +109 -109
  22. package/examples/multi-tenant-context.ts +44 -44
  23. package/examples/node-server.ts +308 -308
  24. package/examples/observer.ts +60 -60
  25. package/examples/platform.ts +115 -115
  26. package/examples/react-app.tsx +362 -362
  27. package/examples/react-observer.tsx +63 -63
  28. package/examples/semantic-memory.ts +60 -60
  29. package/examples/session-advanced.ts +91 -91
  30. package/examples/sqlite-batched-writes.ts +57 -57
  31. package/examples/state-advanced.ts +89 -89
  32. package/examples/store-advanced.ts +117 -117
  33. package/examples/sync.ts +90 -0
  34. package/examples/typed-and-schema.ts +102 -100
  35. package/examples/useObserver.tsx +140 -141
  36. package/global.cjs +4594 -0
  37. package/global.d.ts +8 -0
  38. package/global.js +4532 -0
  39. package/index.cjs +706 -649
  40. package/index.d.ts +1 -0
  41. package/index.js +686 -648
  42. package/llms.txt +72 -4
  43. package/markdown/AUDIT-REPORT.md +135 -0
  44. package/markdown/CACHE.md +100 -0
  45. package/markdown/CHANGELOG.md +243 -0
  46. package/markdown/DEVTOOLS.md +129 -0
  47. package/markdown/DISPATCH.md +177 -0
  48. package/markdown/HISTORY.md +199 -0
  49. package/markdown/IDB.md +178 -0
  50. package/markdown/IMPORT.md +153 -0
  51. package/markdown/INSPECT.md +123 -0
  52. package/markdown/LOGGER.md +154 -0
  53. package/markdown/MEMORY-ATTACHMENT.md +96 -0
  54. package/markdown/MEMORY.md +162 -0
  55. package/markdown/OBSERVER.md +209 -0
  56. package/markdown/PLATFORM.md +271 -0
  57. package/markdown/PROJECT.md +311 -0
  58. package/markdown/SCHEMA.md +176 -0
  59. package/markdown/SECURITY.md +330 -0
  60. package/markdown/SESSION.md +165 -0
  61. package/markdown/SQLITE.md +190 -0
  62. package/markdown/STATE.md +160 -0
  63. package/markdown/STORE.md +171 -0
  64. package/markdown/SYNC.md +319 -0
  65. package/markdown/TYPED.md +165 -0
  66. package/markdown/USEOBSERVER.md +257 -0
  67. package/modules/redux.cjs +561 -374
  68. package/modules/redux.cjs.map +1 -1
  69. package/modules/redux.js +561 -374
  70. package/modules/redux.js.map +1 -1
  71. package/package.json +13 -3
  72. package/types/env.d.ts +19 -9
  73. package/types/exports.d.ts +20 -0
  74. package/types/history.d.ts +13 -1
  75. package/types/memorio.d.ts +17 -5
  76. package/types/mutation.d.ts +75 -0
@@ -0,0 +1,165 @@
1
+ > **Status:** Published
2
+ > **Date:** 2026-09-12
3
+ > **Deciders:** Memorio 5.x Core Team
4
+ > **Scope**: API Reference
5
+ > **Standard**: Memorio API Specification v5
6
+ >
7
+ ---
8
+ # Typed Stores - Memorio
9
+
10
+ > ✅ **Universal**: Works in Browser, Node.js, Deno, and Edge Workers
11
+
12
+ `memorio.typed<T>()` returns the global `state` proxy cast to a TypeScript type `T`, giving you **compile-time** type safety on every access and mutation.
13
+
14
+ It's a **zero-runtime-cost** wrapper: the returned object is the *exact same* Proxy as `globalThis.state`, just with TypeScript types applied via a generic.
15
+
16
+ ---
17
+
18
+ ## Quick Start
19
+
20
+ ```typescript
21
+ import { memorio, state, typed, useObserver } from 'memorio'
22
+
23
+ interface AppState {
24
+ user: { name: string; age: number; email: string }
25
+ theme: 'light' | 'dark'
26
+ items: string[]
27
+ }
28
+
29
+ const app = memorio.typed<AppState>()
30
+
31
+ // Type-checked at compile time:
32
+ app.user = { name: 'Sara', age: 30, email: 'sara@test.com' }
33
+ app.theme = 'dark'
34
+
35
+ // TypeScript errors:
36
+ // app.user = { name: 42 } // age missing, name wrong type
37
+ // app.theme = 'purple' // not a valid literal
38
+ ```
39
+
40
+ ---
41
+
42
+ ## Why use typed stores?
43
+
44
+ | Without typed | With `memorio.typed<T>()` |
45
+ |---|---|
46
+ | `state.user = { name: 42 }` - runs silently, bug at runtime | `app.user = { name: 42 }` - TypeScript error at compile time |
47
+ | No autocomplete on `state.user.email` | Full IntelliSense: properties, types, method suggestions |
48
+ | Rename `user` to `profile` - no compiler warning anywhere | Every `app.user` access flagged as an error |
49
+ | AI-generated code lacks guardrails | AI gets autocomplete and type feedback inline |
50
+
51
+ ---
52
+
53
+ ## Combine with Schema Validation
54
+
55
+ Typed stores catch type errors at compile time; schema validation catches invalid values at runtime. Together they form a **defense-in-depth** strategy:
56
+
57
+ ```typescript
58
+ import { memorio, state } from 'memorio'
59
+
60
+ interface ProfileState {
61
+ profile: { bio: string; avatar?: string }
62
+ }
63
+
64
+ const app = memorio.typed<ProfileState>()
65
+
66
+ memorio.registerSchema('profile', {
67
+ type: 'object',
68
+ required: ['bio'],
69
+ properties: {
70
+ bio: { type: 'string', min: 1 },
71
+ avatar: { type: 'string' }
72
+ }
73
+ })
74
+
75
+ app.profile = { bio: 'Developer', avatar: 'pic.png' } // ✅ type + schema pass
76
+ app.profile = { avatar: 'pic.png' } // ❌ TypeScript: bio missing
77
+ // ❌ Runtime: bio required
78
+ ```
79
+
80
+ See [Schema Validation](SCHEMA.md) for runtime validation details.
81
+
82
+ ---
83
+
84
+ ## Named import variant
85
+
86
+ `typed` is also available as a named export if you prefer explicit dependencies:
87
+
88
+ ```typescript
89
+ import { typed } from 'memorio'
90
+
91
+ const app = typed<AppState>()
92
+ ```
93
+
94
+ The `memorio` namespace object is the same across both usage styles - named imports and the `memorio/global` entrypoint share the same runtime instances.
95
+
96
+ ---
97
+
98
+ ## Full API
99
+
100
+ | Method | Parameters | Returns | Description |
101
+ |--------|-----------|---------|-------------|
102
+ | `memorio.typed<T>()` | Generic type `T` | `T` | Returns the global `state` proxy cast to `T` |
103
+
104
+ The returned object shares the same identity as `globalThis.state`:
105
+
106
+ ```typescript
107
+ const app = memorio.typed<AppState>()
108
+ console.debug(app === state) // true - same Proxy instance
109
+ ```
110
+
111
+ ---
112
+
113
+ ## React + typed stores
114
+
115
+ Pair with the `useObserver` hook for type-safe, reactive React components:
116
+
117
+ ```tsx
118
+ import { memorio, state, useObserver } from 'memorio'
119
+ import { useReducer } from 'react'
120
+
121
+ interface AppState {
122
+ user: { name: string; age: number }
123
+ theme: 'light' | 'dark'
124
+ }
125
+
126
+ const app = memorio.typed<AppState>()
127
+
128
+ function UserProfile() {
129
+ const [, forceUpdate] = useReducer(x => x + 1, 0)
130
+
131
+ useObserver(forceUpdate, [state.user.name])
132
+
133
+ return (
134
+ <div>
135
+ <h1>{app.user.name}</h1>
136
+ <span>Theme: {app.theme}</span>
137
+ </div>
138
+ )
139
+ }
140
+ ```
141
+
142
+ ---
143
+
144
+ ## Best Practices
145
+
146
+ 1. **Define your AppState at the root** of your app and import it everywhere:
147
+
148
+ ```typescript
149
+ // types/app-state.ts
150
+ export interface AppState {
151
+ user: { name: string; email: string }
152
+ theme: 'light' | 'dark'
153
+ }
154
+ ```
155
+
156
+ ```typescript
157
+ // anywhere in your app
158
+ import { memorio } from 'memorio'
159
+ import type { AppState } from '../types/app-state'
160
+ const app = memorio.typed<AppState>()
161
+ ```
162
+
163
+ 2. **Layer schema validation on top** for runtime safety, especially for data coming from APIs or user input.
164
+
165
+ 3. **Use alongside `memorio.help()`** (via `import 'memorio/global'`) to list available globals during development.
@@ -0,0 +1,257 @@
1
+ > **Status:** Published
2
+ > **Date:** 2026-09-12
3
+ > **Deciders:** Memorio 5.x Core Team
4
+ > **Scope**: API Reference
5
+ > **Standard**: Memorio API Specification v5
6
+ >
7
+ ---
8
+ # useObserver - Memorio
9
+
10
+ > ⚛️ **React Only**: This is a React hook and only works within React components
11
+
12
+ useObserver is a React hook for observing state changes. It automatically subscribes to state changes and includes powerful auto-discovery features.
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install memorio
18
+ ```
19
+
20
+ ```javascript
21
+ import { useObserver, state } from 'memorio';
22
+ ```
23
+
24
+ > **Global API**: `import 'memorio/global'` is the opt-in entrypoint that also exposes `state`, `store`, `session`, `cache`, `idb`, `sqlite`, `observer`, and `useObserver` on `globalThis`.
25
+
26
+ ---
27
+
28
+ ## Quick Examples
29
+
30
+ ### Example 1: Basic Usage
31
+
32
+ ```javascript
33
+ function Counter() {
34
+ // Direct values work! ✅
35
+ useObserver(() => {
36
+ console.debug('Counter changed:', state.counter);
37
+ }, [state.counter]);
38
+
39
+ return <div>{state.counter}</div>;
40
+ }
41
+ ```
42
+
43
+ ### Auto-Discovery (Magic Mode)
44
+
45
+ ```javascript
46
+ // Pass your callback WITHOUT dependencies - it auto-discovers!
47
+ function MyComponent() {
48
+ useObserver(() => {
49
+ // This will automatically track ALL state properties used inside
50
+ console.debug('Something changed:', state.user.name, state.items.length);
51
+ });
52
+
53
+ return <div>{state.user.name}</div>;
54
+ }
55
+ ```
56
+
57
+ ### Example 2: Intermediate
58
+
59
+ ```javascript
60
+ function UserProfile() {
61
+ const [localState, setLocalState] = useState(null);
62
+
63
+ useObserver(() => {
64
+ setLocalState(state.user);
65
+ }, [state.user]);
66
+
67
+ return <div>{localState?.name}</div>;
68
+ }
69
+ ```
70
+
71
+ ### Example 3: Advanced
72
+
73
+ ```javascript
74
+ // Multiple watchers with array - works with direct values
75
+ function MultiWatch() {
76
+ useObserver(() => {
77
+ console.debug('A or B changed:', state.a, state.b);
78
+ }, [state.a, state.b]); // Direct values work!
79
+
80
+ return <div>{state.a} - {state.b}</div>;
81
+ }
82
+
83
+ // With string path (for store)
84
+ function StoreWatcher() {
85
+ useObserver(() => {
86
+ console.debug('Store changed');
87
+ }, 'store.userPreferences');
88
+
89
+ return <div />;
90
+ }
91
+ ```
92
+
93
+ ---
94
+
95
+ ## API Reference
96
+
97
+ ### useObserver(callback, deps)
98
+
99
+ | Parameter | Type | Description |
100
+ | --------- | ---- | ----------- |
101
+ | `callback` | `function` | Function to run on change |
102
+ | `deps` | `function \| string \| array \| proxy` | State path(s) to watch. Supports: |
103
+ | | | - Direct values: `state.counter` |
104
+ | | | - String paths: `'state.counter'` |
105
+ | | | - Arrow functions: `() => state.counter` |
106
+ | | | - Arrays: `[state.a, state.b]` or `['state.a', 'state.b']` |
107
+ | | | - Optional chaining: `[state?.one]` |
108
+
109
+ ### Primitive Values
110
+
111
+ Direct primitive values are now fully supported:
112
+
113
+ ```javascript
114
+ // Direct values work with primitives ✅
115
+ useObserver(() => { console.debug('changed') }, [state.counter])
116
+
117
+ // Arrays of primitives work ✅
118
+ useObserver(() => { console.log(state.a, state.b) }, [state.a, state.b])
119
+
120
+ // Optional chaining works ✅
121
+ useObserver(() => { console.log(state?.one) }, [state?.one])
122
+
123
+ // Strings still work ✅
124
+ useObserver(() => { console.debug('changed') }, ['state.counter'])
125
+
126
+ // Functions still work ✅
127
+ useObserver(() => { console.debug('changed') }, [() => state.counter])
128
+ ```
129
+
130
+ ### Callback Parameters
131
+
132
+ ```javascript
133
+ // Single value (no array needed)
134
+ useObserver(
135
+ () => {
136
+ console.debug('Changed:', state.key);
137
+ }, state.key // Single value works!
138
+ );
139
+
140
+ // Array of values
141
+ useObserver(
142
+ () => {
143
+ console.debug('Changed:', state.key);
144
+ }, [state.key] // Array also works!
145
+ );
146
+ ```
147
+
148
+ ### Auto-Discovery Mode
149
+
150
+ When `deps` is omitted, useObserver automatically discovers all state properties accessed inside the callback:
151
+
152
+ ```javascript
153
+ // No deps needed - magic auto-discovery!
154
+ useObserver(() => {
155
+ // Automatically tracks state.user, state.items, state.counter
156
+ console.debug(state.user.name, state.items.length, state.counter);
157
+ },[]);
158
+ ```
159
+
160
+ Returns a cleanup function:
161
+
162
+ ## useObserver vs observer
163
+
164
+ | Feature | observer | useObserver |
165
+ | ------- | -------- | ----------- |
166
+ | Framework | Vanilla JS | React |
167
+ | Auto-cleanup | Manual | Auto |
168
+ | React lifecycle | No | Yes |
169
+
170
+ ---
171
+
172
+ ## Common Patterns
173
+
174
+ ### Sync with useState (Recommended for Primitives)
175
+
176
+ ```javascript
177
+ function CounterComponent() {
178
+ // Sync memorio state with React state
179
+ const [counter, setCounter] = useState(state.counter)
180
+
181
+ // React useEffect works correctly with primitive values
182
+ useEffect(() => {
183
+ console.log('Counter changed:', counter)
184
+ }, [counter])
185
+
186
+ // Direct values now work with primitives!
187
+ useObserver(() => {
188
+ setCounter(state.counter)
189
+ }, [state.counter]) // ✅ Works now!
190
+
191
+ return (
192
+ <div>
193
+ <button onClick={() => { state.counter++ }}>Increment</button>
194
+ <span>{counter}</span>
195
+ </div>
196
+ )
197
+ }
198
+ ```
199
+
200
+ ### Safe Access with Optional Chaining (Protection)
201
+
202
+ ```javascript
203
+ // Optional chaining is supported - protects against errors
204
+ useObserver(() => {
205
+ if (test?.one) {
206
+ console.log(test.one)
207
+ }
208
+ }, [test?.one])
209
+
210
+ // Works with objects
211
+ function SafeComponent() {
212
+ const [test, setTest] = useState(state.test)
213
+
214
+ useEffect(() => {
215
+ if (test?.one) {
216
+ console.log('test.one:', test.one)
217
+ }
218
+ }, [test?.one])
219
+
220
+ useObserver(() => {
221
+ if (state.test?.one) {
222
+ setTest(state.test)
223
+ }
224
+ }, ['state.test.one'])
225
+
226
+ return <div>{test?.one || 'Loading...'}</div>
227
+ }
228
+ ```
229
+
230
+ ### Multiple Watchers
231
+
232
+ ```javascript
233
+ // Watch multiple properties with strings
234
+ useObserver(() => {
235
+ console.log(state.a, state.b)
236
+ }, ['state.a', 'state.b'])
237
+
238
+ // Watch multiple properties with functions
239
+ useObserver(() => {
240
+ console.log(state.a, state.b)
241
+ }, [() => state.a, () => state.b])
242
+
243
+ // Watch with auto-discovery
244
+ useObserver(() => {
245
+ console.log(state.a, state.b) // Automatically tracks both
246
+ }, [])
247
+ ```
248
+
249
+ ---
250
+
251
+ ## Best Practices
252
+
253
+ 1. Always use in React components
254
+ 2. Use auto-discovery for simpler code: `useObserver(() => { ... })`
255
+ 3. No manual cleanup needed - returns cleanup function automatically
256
+ 4. Use with state for reactive UI
257
+ 5. Check console for auto-discovery logs