memorio 4.9.35 → 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 +307 -359
  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 +700 -678
  40. package/index.d.ts +1 -0
  41. package/index.js +680 -677
  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 +320 -167
  68. package/modules/redux.cjs.map +1 -1
  69. package/modules/redux.js +320 -167
  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
@@ -1,100 +1,102 @@
1
- /**
2
- * MEMORIO TYPED STORES + SCHEMA VALIDATION - LIVE EXAMPLES
3
- *
4
- * This file demonstrates every code snippet used in docs/markdown/SCHEMA.md
5
- * and docs/markdown/TYPED.md. It is real, compiling TypeScript.
6
- *
7
- * Primary usage: `import 'memorio'` (side-effect import) makes all globals
8
- * available, including the `memorio` namespace object.
9
- *
10
- * @module memorio/examples/typed-and-schema
11
- */
12
-
13
- import 'memorio'
14
-
15
- // =============================================================================
16
- // TYPED STORES - compile-time type safety on the global `state` proxy
17
- // =============================================================================
18
-
19
- interface AppState {
20
- user: { name: string; age: number; email: string }
21
- theme: 'light' | 'dark'
22
- items: string[]
23
- }
24
-
25
- const app = memorio.typed<AppState>()
26
-
27
- app.user = { name: 'Sara', age: 30, email: 'sara@test.com' }
28
- app.theme = 'dark'
29
- app.items = ['apple', 'banana']
30
-
31
- state.user.name = 'Luigi'
32
- state.counter = 100
33
- const currentTheme: 'light' | 'dark' = app.theme
34
- void currentTheme
35
-
36
- // =============================================================================
37
- // SCHEMA VALIDATION - runtime guards that reject invalid state writes
38
- // =============================================================================
39
-
40
- memorio.registerSchema('user', {
41
- type: 'object',
42
- required: ['name', 'email'],
43
- properties: {
44
- name: { type: 'string', min: 1 },
45
- email: { type: 'string', pattern: /^[^@]+@[^@]+$/ },
46
- age: { type: 'number', min: 0, max: 150 }
47
- }
48
- })
49
-
50
- memorio.registerSchema('theme', { enum: ['light', 'dark'] })
51
-
52
- memorio.registerSchema('items', {
53
- type: 'array',
54
- validator: (val: any) => Array.isArray(val) && val.every((i: any) => typeof i === 'string')
55
- ? true
56
- : 'items must be an array of strings'
57
- })
58
-
59
- memorio.registerSchema('counter', (val: any) => {
60
- if (typeof val !== 'number') return 'counter must be a number'
61
- if (val < 0) return 'counter must be >= 0'
62
- return true
63
- })
64
-
65
- // These writes are rejected at runtime:
66
- state.user = { name: 'Sara' } // missing 'email' - rejected
67
- state.theme = 'purple' // not in enum - rejected
68
- state.counter = -5 // fails custom validator - rejected
69
-
70
- // These pass:
71
- state.user = { name: 'Sara', email: 'sara@test.com', age: 30 }
72
- state.theme = 'light'
73
- state.counter = 5
74
-
75
- // Manual validation:
76
- memorio.validate('user', { name: 'Sara', email: 'sara@test.com' })
77
- memorio.validate('theme', 'dark')
78
-
79
- memorio.listSchemas()
80
- memorio.unregisterSchema('counter')
81
-
82
- // =============================================================================
83
- // TYPED + SCHEMA - combine both for full safety
84
- // =============================================================================
85
-
86
- memorio.registerSchema('profile', {
87
- type: 'object',
88
- required: ['bio'],
89
- properties: {
90
- bio: { type: 'string', min: 1 },
91
- avatar: { type: 'string' }
92
- }
93
- })
94
-
95
- interface ProfileState {
96
- profile: { bio: string; avatar?: string }
97
- }
98
-
99
- const typedProfile = memorio.typed<ProfileState>()
100
- typedProfile.profile = { bio: 'Developer', avatar: 'pic.png' }
1
+ /**
2
+ * MEMORIO TYPED STORES + SCHEMA VALIDATION - LIVE EXAMPLES
3
+ *
4
+ * This file demonstrates every code snippet used in docs/markdown/SCHEMA.md
5
+ * and docs/markdown/TYPED.md. It is real, compiling TypeScript.
6
+ *
7
+ * Primary usage: explicit named imports give you both the APIs and the
8
+ * `memorio` namespace object without polluting `globalThis`.
9
+ *
10
+ * @module memorio/examples/typed-and-schema
11
+ */
12
+
13
+ import { memorio, state } from 'memorio'
14
+
15
+ // =============================================================================
16
+ // TYPED STORES - compile-time type safety on the state proxy
17
+ // =============================================================================
18
+
19
+ interface AppState {
20
+ user: { name: string; age: number; email: string }
21
+ theme: 'light' | 'dark'
22
+ items: string[]
23
+ }
24
+
25
+ const app = memorio.typed<AppState>()
26
+
27
+ app.user = { name: 'Sara', age: 30, email: 'sara@test.com' }
28
+ app.theme = 'dark'
29
+ app.items = ['apple', 'banana']
30
+
31
+ state.user.name = 'Luigi'
32
+ state.counter = 100
33
+ const currentTheme: 'light' | 'dark' = app.theme
34
+ void currentTheme
35
+
36
+ // =============================================================================
37
+ // SCHEMA VALIDATION - runtime guards that reject invalid state writes
38
+ // =============================================================================
39
+
40
+ // `app` shares the same identity as `state` - same Proxy instance
41
+
42
+ memorio.registerSchema('user', {
43
+ type: 'object',
44
+ required: ['name', 'email'],
45
+ properties: {
46
+ name: { type: 'string', min: 1 },
47
+ email: { type: 'string', pattern: /^[^@]+@[^@]+$/ },
48
+ age: { type: 'number', min: 0, max: 150 }
49
+ }
50
+ })
51
+
52
+ memorio.registerSchema('theme', { enum: ['light', 'dark'] })
53
+
54
+ memorio.registerSchema('items', {
55
+ type: 'array',
56
+ validator: (val: any) => Array.isArray(val) && val.every((i: any) => typeof i === 'string')
57
+ ? true
58
+ : 'items must be an array of strings'
59
+ })
60
+
61
+ memorio.registerSchema('counter', (val: any) => {
62
+ if (typeof val !== 'number') return 'counter must be a number'
63
+ if (val < 0) return 'counter must be >= 0'
64
+ return true
65
+ })
66
+
67
+ // These writes are rejected at runtime:
68
+ state.user = { name: 'Sara' } // missing 'email' - rejected
69
+ state.theme = 'purple' // not in enum - rejected
70
+ state.counter = -5 // fails custom validator - rejected
71
+
72
+ // These pass:
73
+ state.user = { name: 'Sara', email: 'sara@test.com', age: 30 }
74
+ state.theme = 'light'
75
+ state.counter = 5
76
+
77
+ // Manual validation:
78
+ memorio.validate('user', { name: 'Sara', email: 'sara@test.com' })
79
+ memorio.validate('theme', 'dark')
80
+
81
+ memorio.listSchemas()
82
+ memorio.unregisterSchema('counter')
83
+
84
+ // =============================================================================
85
+ // TYPED + SCHEMA - combine both for full safety
86
+ // =============================================================================
87
+
88
+ memorio.registerSchema('profile', {
89
+ type: 'object',
90
+ required: ['bio'],
91
+ properties: {
92
+ bio: { type: 'string', min: 1 },
93
+ avatar: { type: 'string' }
94
+ }
95
+ })
96
+
97
+ interface ProfileState {
98
+ profile: { bio: string; avatar?: string }
99
+ }
100
+
101
+ const typedProfile = memorio.typed<ProfileState>()
102
+ typedProfile.profile = { bio: 'Developer', avatar: 'pic.png' }
@@ -1,141 +1,140 @@
1
- /**
2
- * Memorio useObserver Example
3
- *
4
- * This example demonstrates the useObserver hook for React.
5
- * useObserver automatically tracks state changes and triggers re-renders.
6
- *
7
- * Note: This example requires React to be present in the environment.
8
- * Run in a React environment.
9
- */
10
-
11
- import 'memorio'
12
-
13
- // ============================================
14
- // BASIC USEOBSERVER
15
- // ============================================
16
-
17
- // Example 1: Watch single value
18
- useObserver(callback, [state.value])
19
-
20
- function Counter() {
21
- useObserver(() => {
22
- console.debug('Count changed:', state.count)
23
- }, [state.count])
24
-
25
- return <div>{state.count} </div>
26
- }
27
-
28
- // ============================================
29
- // MULTIPLE DEPENDENCIES
30
- // ============================================
31
-
32
- // Example 2: Watch multiple values
33
- function UserProfile() {
34
- useObserver(() => {
35
- console.debug('User or theme changed')
36
- }, [state.user, state.theme])
37
-
38
- return <div>{state.user.name} </div>
39
- }
40
-
41
- // ============================================
42
- // AUTO-DISCOVERY
43
- // ============================================
44
-
45
- // Example 3: No dependencies - auto-discovers all state access
46
- function AutoDiscovery() {
47
- useObserver(() => {
48
- // Automatically tracks state.user, state.items, state.count
49
- console.debug('Changed:', state.user.name, state.items.length, state.count)
50
- })
51
-
52
- return <div>{state.user.name} </div>
53
- }
54
-
55
- // ============================================
56
- // SYNC WITH USESTATE
57
- // ============================================
58
-
59
- // Example 4: Sync with useState
60
- function SyncedComponent() {
61
- const [localData, setLocalData] = useState(null)
62
-
63
- useObserver((newValue) => {
64
- setLocalData(newValue)
65
- }, [state.data])
66
-
67
- return <div>{localData} </div>
68
- }
69
-
70
- // ============================================
71
- // PRACTICAL EXAMPLE
72
- // ============================================
73
-
74
- // Real-world React component example:
75
- import 'memorio'
76
-
77
- function TodoApp() {
78
- // Track todos
79
- useObserver(() => {
80
- console.debug('Todos updated:', state.todos)
81
- // Optionally save to store
82
- store.set('todos', state.todos)
83
- }, [state.todos])
84
-
85
- // Track filter
86
- useObserver(() => {
87
- console.debug('Filter changed:', state.filter)
88
- }, [state.filter])
89
-
90
- const addTodo = (text) => {
91
- state.todos = [...(state.todos || []), { text, done: false }]
92
- }
93
-
94
- const toggleTodo = (index) => {
95
- const todos = [...state.todos]
96
- todos[index].done = !todos[index].done
97
- state.todos = todos
98
- }
99
-
100
- const filteredTodos = (state.todos || []).filter(t =>
101
- state.filter === 'all' ||
102
- (state.filter === 'done' && t.done) ||
103
- (state.filter === 'todo' && !t.done)
104
- )
105
-
106
- return (
107
- <div>
108
- <select
109
- value={state.filter}
110
- onChange={e => state.filter = e.target.value}
111
- >
112
- <option value="all" > All </option>
113
- < option value="done" > Done </option>
114
- < option value="todo" > Todo </option>
115
- </select>
116
- <ul>
117
- {
118
- filteredTodos.map((todo, i) => (
119
- <li
120
- key={i}
121
- onClick={() => toggleTodo(i)}
122
- style={{ textDecoration: todo.done ? 'line-through' : 'none' }
123
- }
124
- >
125
- {todo.text}
126
- </li>
127
- ))}
128
- </ul>
129
- < input
130
- onKeyDown={e => {
131
- if (e.key === 'Enter') {
132
- addTodo(e.target.value)
133
- e.target.value = ''
134
- }
135
- }}
136
- />
137
- </div>
138
- )
139
- }
140
-
141
- console.debug('useObserver example - run in React environment!')
1
+ /**
2
+ * Memorio useObserver Example
3
+ *
4
+ * This example demonstrates the useObserver hook for React.
5
+ * useObserver automatically tracks state changes and triggers re-renders.
6
+ *
7
+ * Note: This example requires React to be present in the environment.
8
+ * Run in a React environment (e.g. Vite/CRA), not directly with ts-node.
9
+ */
10
+
11
+ import { useState } from 'react'
12
+ import { useObserver, state, store } from 'memorio'
13
+
14
+ // ============================================
15
+ // BASIC USEOBSERVER
16
+ // ============================================
17
+
18
+ function Counter() {
19
+ useObserver(() => {
20
+ console.debug('Count changed:', state.count)
21
+ }, [state.count])
22
+
23
+ return <div>{state.count}</div>
24
+ }
25
+
26
+ // ============================================
27
+ // MULTIPLE DEPENDENCIES
28
+ // ============================================
29
+
30
+ // Example 2: Watch multiple values
31
+ function UserProfile() {
32
+ useObserver(() => {
33
+ console.debug('User or theme changed')
34
+ }, [state.user, state.theme])
35
+
36
+ return <div>{state.user.name}</div>
37
+ }
38
+
39
+ // ============================================
40
+ // AUTO-DISCOVERY
41
+ // ============================================
42
+
43
+ // Example 3: No dependencies - auto-discovers all state access
44
+ function AutoDiscovery() {
45
+ useObserver(() => {
46
+ // Automatically tracks state.user, state.items, state.count
47
+ console.debug('Changed:', state.user.name, state.items.length, state.count)
48
+ })
49
+
50
+ return <div>{state.user.name}</div>
51
+ }
52
+
53
+ // ============================================
54
+ // SYNC WITH USESTATE
55
+ // ============================================
56
+
57
+ // Example 4: Sync with useState
58
+ function SyncedComponent() {
59
+ const [localData, setLocalData] = useState(null)
60
+
61
+ useObserver((newValue: unknown) => {
62
+ setLocalData(newValue)
63
+ }, [state.data])
64
+
65
+ return <div>{localData}</div>
66
+ }
67
+
68
+ // ============================================
69
+ // PRACTICAL EXAMPLE
70
+ // ============================================
71
+
72
+ // Real-world React component example:
73
+ interface Todo {
74
+ text: string
75
+ done: boolean
76
+ }
77
+
78
+ function TodoApp() {
79
+ // Track todos
80
+ useObserver(() => {
81
+ console.debug('Todos updated:', state.todos)
82
+ // Optionally save to store
83
+ store.set('todos', state.todos)
84
+ }, [state.todos])
85
+
86
+ // Track filter
87
+ useObserver(() => {
88
+ console.debug('Filter changed:', state.filter)
89
+ }, [state.filter])
90
+
91
+ const addTodo = (text: string) => {
92
+ state.todos = [...(state.todos || []), { text, done: false }]
93
+ }
94
+
95
+ const toggleTodo = (index: number) => {
96
+ const todos: Todo[] = [...state.todos]
97
+ todos[index].done = !todos[index].done
98
+ state.todos = todos
99
+ }
100
+
101
+ const filteredTodos: Todo[] = (state.todos || []).filter((t: Todo) =>
102
+ state.filter === 'all' ||
103
+ (state.filter === 'done' && t.done) ||
104
+ (state.filter === 'todo' && !t.done)
105
+ )
106
+
107
+ return (
108
+ <div>
109
+ <select
110
+ value={state.filter}
111
+ onChange={e => { state.filter = e.target.value }}
112
+ >
113
+ <option value="all">All</option>
114
+ <option value="done">Done</option>
115
+ <option value="todo">Todo</option>
116
+ </select>
117
+ <ul>
118
+ {filteredTodos.map((todo, i) => (
119
+ <li
120
+ key={i}
121
+ onClick={() => toggleTodo(i)}
122
+ style={{ textDecoration: todo.done ? 'line-through' : 'none' }}
123
+ >
124
+ {todo.text}
125
+ </li>
126
+ ))}
127
+ </ul>
128
+ <input
129
+ onKeyDown={e => {
130
+ if (e.key === 'Enter') {
131
+ addTodo((e.target as HTMLInputElement).value)
132
+ ;(e.target as HTMLInputElement).value = ''
133
+ }
134
+ }}
135
+ />
136
+ </div>
137
+ )
138
+ }
139
+
140
+ export { Counter, UserProfile, AutoDiscovery, SyncedComponent, TodoApp }