memorio 4.8.0 → 4.9.5

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.
@@ -1,116 +0,0 @@
1
- # Introspection & Inspection - Memorio
2
-
3
- > ✅ **Universal**: Works in Browser, Node.js, Deno, and Edge Workers
4
-
5
- Introspection utilities let you programmatically discover, verify, and read the shape of the global `state` proxy. Essential for AI agents that need to check whether a path exists before writing, or enumerate available keys before reading.
6
-
7
- ---
8
-
9
- ## stateKeys()
10
-
11
- Returns all top-level keys currently on the `state` proxy. Excludes internal properties.
12
-
13
- ```javascript
14
- import 'memorio'
15
-
16
- state.user = { name: 'Sara' }
17
- state.counter = 42
18
-
19
- memorio.stateKeys() // ['user', 'counter']
20
- ```
21
-
22
- ---
23
-
24
- ## pathExists(path)
25
-
26
- Checks whether a dotted path exists in state. Returns `true` if the path resolves to a non-undefined value.
27
-
28
- ```javascript
29
- state.user = { name: 'Sara', profile: { age: 30 } }
30
-
31
- memorio.pathExists('user') // true
32
- memorio.pathExists('user.name') // true
33
- memorio.pathExists('user.profile') // true
34
- memorio.pathExists('user.profile.age') // true
35
- memorio.pathExists('user.age') // false
36
- memorio.pathExists('nonexistent') // false
37
- ```
38
-
39
- This is critical for AI agents: always check `pathExists` before writing to a nested path to avoid creating unintended intermediate objects.
40
-
41
- ---
42
-
43
- ## stateType(path)
44
-
45
- Returns the runtime type of the value at a given state path.
46
-
47
- ```javascript
48
- state.count = 42
49
- state.name = 'Sara'
50
- state.items = [1, 2, 3]
51
-
52
- memorio.stateType('count') // 'number'
53
- memorio.stateType('name') // 'string'
54
- memorio.stateType('items') // 'array'
55
- memorio.stateType('missing') // 'undefined'
56
- ```
57
-
58
- ---
59
-
60
- ## stateGet(path)
61
-
62
- Returns the value at a dotted path, deep-cloned to prevent accidental mutation of state.
63
-
64
- ```javascript
65
- state.user = { name: 'Sara', tags: ['admin'] }
66
-
67
- const user = memorio.stateGet('user') // { name: 'Sara', tags: ['admin'] }
68
- user.name = 'Luigi' // mutates the clone, not state
69
- state.user.name // still 'Sara'
70
- ```
71
-
72
- ---
73
-
74
- ## stateSchema()
75
-
76
- Generates a full schema report of the current state tree — every path with its type and whether it's defined.
77
-
78
- ```javascript
79
- state.user = { name: 'Sara', age: 30 }
80
- state.theme = 'dark'
81
-
82
- memorio.stateSchema()
83
- // [
84
- // { path: 'user', type: 'object', defined: true },
85
- // { path: 'user.name', type: 'string', defined: true },
86
- // { path: 'user.age', type: 'number', defined: true },
87
- // { path: 'theme', type: 'string', defined: true }
88
- // ]
89
- ```
90
-
91
- This is the **most useful for AI agents** — it gives a complete picture of what's in state and what types the values are, in a single call. Perfect for:
92
- - Discovering available state before generating code
93
- - Validating that expected paths exist
94
- - Understanding the shape of nested objects
95
-
96
- ---
97
-
98
- ## Full API
99
-
100
- | Method | Parameters | Returns | Description |
101
- |--------|-----------|---------|-------------|
102
- | `memorio.stateKeys()` | none | `string[]` | Top-level state keys |
103
- | `memorio.pathExists(path)` | `string` | `boolean` | Whether a path resolves to a value |
104
- | `memorio.stateType(path)` | `string` | `string` | Runtime type at path |
105
- | `memorio.stateGet(path)` | `string` | `any` | Deep-cloned value at path |
106
- | `memorio.stateSchema()` | none | `SchemaEntry[]` | Full state tree report |
107
-
108
- ---
109
-
110
- ## How It Works
111
-
112
- All introspection functions read from the global `state` proxy via `deepRaw()` — the same function used internally by the state proxy to unwrap itself before storing. This ensures consistent, non-proxied values are returned.
113
-
114
- - `pathExists` and `stateGet` split the path on `.` and traverse the state tree.
115
- - `stateSchema` recursively walks the state object, collecting every path and its type.
116
- - All returned values from `stateGet` and `snapshot` are deep clones (via JSON round-trip) to prevent accidental mutation.
@@ -1,147 +0,0 @@
1
- # Memorio Logger
2
-
3
- > 🖥️ **Browser Only**: This feature is only available in browser console
4
-
5
- Automatic logging middleware for tracking all state changes in Memorio.
6
-
7
- ## Overview
8
-
9
- The logger automatically tracks all operations (set, delete, clear) across all modules:
10
- - State
11
- - Store
12
- - Session
13
- - Cache
14
-
15
- ## Configuration
16
-
17
- ### configure(options)
18
-
19
- Configure the logger.
20
-
21
- ```javascript
22
- memorio.logger.configure({
23
- enabled: true, // Enable/disable logging
24
- logToConsole: true, // Log to browser console
25
- customHandler: function(entry) { ... }, // Custom handler
26
- modules: ['state', 'store', 'session', 'cache'], // Modules to log
27
- maxEntries: 1000 // Maximum log history size
28
- })
29
- ```
30
-
31
- ### enable()
32
-
33
- Enable logging.
34
-
35
- ```javascript
36
- memorio.logger.enable()
37
- ```
38
-
39
- ### disable()
40
-
41
- Disable logging.
42
-
43
- ```javascript
44
- memorio.logger.disable()
45
- ```
46
-
47
- ## Methods
48
-
49
- ### getHistory()
50
-
51
- Get all log entries.
52
-
53
- ```javascript
54
- const history = memorio.logger.getHistory()
55
- // Returns array of LogEntry objects
56
- ```
57
-
58
- ### getStats()
59
-
60
- Get statistics about logged operations.
61
-
62
- ```javascript
63
- const stats = memorio.logger.getStats()
64
- // Returns: { total, state, store, session, cache, set, get, delete, clear }
65
- ```
66
-
67
- ### clearHistory()
68
-
69
- Clear log history.
70
-
71
- ```javascript
72
- memorio.logger.clearHistory()
73
- ```
74
-
75
- ### exportLogs()
76
-
77
- Export logs as JSON string.
78
-
79
- ```javascript
80
- const json = memorio.logger.exportLogs()
81
- ```
82
-
83
- ## Log Entry Structure
84
-
85
- ```javascript
86
- {
87
- timestamp: "2026-02-18T12:00:00.000Z",
88
- module: "state",
89
- action: "set",
90
- path: "user.name",
91
- value: "John",
92
- previousValue: "Jane"
93
- }
94
- ```
95
-
96
- ## Examples
97
-
98
- ### Basic usage
99
-
100
- ```javascript
101
- // Logging is enabled by default
102
- state.user = { name: 'John' }
103
- // Console: [Memorio:STATE] set user → value: { name: 'John' }
104
- ```
105
-
106
- ### Get statistics
107
-
108
- ```javascript
109
- const stats = memorio.logger.getStats()
110
- console.debug(stats)
111
- // { total: 15, state: 5, store: 3, session: 2, cache: 5, set: 10, get: 0, delete: 3, clear: 2 }
112
- ```
113
-
114
- ### Disable specific modules
115
-
116
- ```javascript
117
- memorio.logger.configure({
118
- modules: ['state'] // Only log state changes
119
- })
120
- ```
121
-
122
- ### Custom handler
123
-
124
- ```javascript
125
- memorio.logger.configure({
126
- customHandler: (entry) => {
127
- // Send to analytics
128
- analytics.track('memorio_change', entry)
129
- }
130
- })
131
- ```
132
-
133
- ### Export and analyze
134
-
135
- ```javascript
136
- // Get all logs
137
- const logs = memorio.logger.getHistory()
138
-
139
- // Filter by module
140
- const stateLogs = logs.filter(l => l.module === 'state')
141
-
142
- // Filter by action
143
- const setOperations = logs.filter(l => l.action === 'set')
144
-
145
- // Export for debugging
146
- console.debug(memorio.logger.exportLogs())
147
- ```
@@ -1,95 +0,0 @@
1
- # Node Attachment System
2
-
3
- `memorio.memory` extends with a **Node Attachment System** allowing memory elements to dynamically attach, reference, or connect to other memory elements at runtime.
4
-
5
- This is an **extension**, not a replacement, of existing memory semantics.
6
-
7
- ## Concepts
8
-
9
- ```text
10
- Memory
11
- └── Node
12
- ├── identity
13
- ├── value
14
- ├── metadata
15
- └── relationships
16
- └── Edge
17
- ├── target
18
- ├── relation
19
- ├── metadata
20
- ├── confidence
21
- └── lifecycle
22
- ```
23
-
24
- ## API
25
-
26
- ```ts
27
- const user = await memory.remember("user", { name: "Alice" })
28
- const project = await memory.remember("project", { name: "Memorio" })
29
-
30
- await user.connect(project, { relation: "works-on", confidence: 0.95 })
31
- await user.attach(project) // → connect with relation "attached-to"
32
-
33
- const related = await user.related({ direction: "both", relation: "works-on" })
34
- const tree = await user.traverse({ depth: 3 })
35
- ```
36
-
37
- ### Methods
38
-
39
- | Method | Description |
40
- |--------|-------------|
41
- | `node.connect(target, opts?)` | Create a directed relationship |
42
- | `node.disconnect(target, opts?)` | Remove a relationship |
43
- | `node.related(opts?)` | Query related nodes |
44
- | `node.traverse(opts?)` | Bounded graph traversal |
45
- | `memory.connect(source, target, opts?)` | Low-level connect |
46
- | `memory.disconnect(source, target, opts?)` | Low-level disconnect |
47
-
48
- ## Scopes
49
-
50
- Relationship visibility respects memory scopes — a query in one scope cannot leak inaccessible nodes from another.
51
-
52
- ## Persistence
53
-
54
- Relationships use **IDs**, never embedded objects:
55
-
56
- ```json
57
- {
58
- "id": "user",
59
- "relationships": [
60
- { "target": "project", "relation": "works-on" }
61
- ]
62
- }
63
- ```
64
-
65
- ## Lifecycle
66
-
67
- - **TTL**: independent per node/edge — does not propagate
68
- - **Confidence**: independent — node and edge have separate confidence values
69
- - **Deletion**: deleting a node removes its edges (default policy)
70
- - **Cycles**: supported with visited-set protection during traversal
71
- - **Dangling references**: `retain` by default (configurable)
72
-
73
- ## Security
74
-
75
- Relationship traversal inherits the same scope/access rules as direct retrieval. A user cannot gain access to Node B merely because Node A connects to it.
76
-
77
- ## Experimental Substrate Evaluation
78
-
79
- Runtime substrate choices (Object Graph, WeakMap, DOM) are under benchmark evaluation. See:
80
-
81
- - [Leak Detection Protocol](../experimental/memory-substrates/LEAK-DETECTION.md)
82
-
83
- ## Serialization
84
-
85
- Nodes serialize to IDs only — never recursively embedded graphs.
86
-
87
- ## Performance
88
-
89
- - `O(1)` indexed lookup for direct node retrieval
90
- - Graph traversal only on explicit request
91
- - Indexable by `source`, `target`, `relation`
92
-
93
- ## Backward Compatibility
94
-
95
- Existing APIs (`remember`, `get`, `forget`, `search`) continue to work unchanged. A node-enabled memory entry remains usable as a normal memory entry.
@@ -1,155 +0,0 @@
1
- # Memory System
2
-
3
- `memorio.memory` provides a semantic memory layer — a key/value store with type safety, TTL, confidence scoring, tagging, and scope-based persistence.
4
-
5
- ## Core API
6
-
7
- ### `memorio.memory.remember(key, value, opts?)`
8
-
9
- Stores a memory entry.
10
-
11
- ```ts
12
- await memorio.memory.remember('user.name', 'Dario', {
13
- type: 'preference',
14
- confidence: 0.92,
15
- scope: 'local',
16
- ttl: null,
17
- tags: ['user', 'profile'],
18
- source: 'conversation'
19
- })
20
- ```
21
-
22
- | Option | Type | Default | Description |
23
- |--------|------|---------|-------------|
24
- | `id` | `string` | `key` | Custom entry ID |
25
- | `type` | `'fact' \| 'preference' \| 'decision' \| 'task' \| 'context'` | `'fact'` | Semantic classification |
26
- | `confidence` | `number` | `1.0` | Trust score 0.0–1.0 |
27
- | `scope` | `'hot' \| 'session' \| 'local' \| 'durable'` | auto | Storage backend (see below) |
28
- | `ttl` | `number \| null` | `null` | Milliseconds before expiry (`null` = never) |
29
- | `tags` | `string \| string[]` | `[]` | Metadata for filtering |
30
- | `source` | `string` | `undefined` | Origin of the memory |
31
-
32
- ### `memorio.memory.recall(query, opts?)`
33
-
34
- Retrieves a memory by key.
35
-
36
- ```ts
37
- const name = await memorio.memory.recall('user.name')
38
- const highConfidence = await memorio.memory.recall('project', {
39
- minConfidence: 0.8
40
- })
41
- ```
42
-
43
- | Option | Type | Default | Description |
44
- |--------|------|---------|-------------|
45
- | `type` | `MemoryType \| MemoryType[]` | `*` | Filter by type |
46
- | `tags` | `string \| string[]` | `*` | Filter by tags |
47
- | `minConfidence` | `number` | `0` | Minimum confidence threshold |
48
- | `includeObsolete` | `boolean` | `false` | Include expired/superseded entries |
49
-
50
- ### `memorio.memory.update(key, value, opts?)`
51
-
52
- Updates an existing memory. Creates a **superseded copy** of the old entry (preserving history).
53
-
54
- ```ts
55
- await memorio.memory.update('user.name', 'Alice', { confidence: 0.95 })
56
- ```
57
-
58
- ### `memorio.memory.forget(key)`
59
-
60
- Permanently removes a memory.
61
-
62
- ```ts
63
- await memorio.memory.forget('user.temp')
64
- ```
65
-
66
- ### `memorio.memory.context(opts?)`
67
-
68
- Returns ranked, relevant memories. Uses recency × confidence × type/scope boost algorithm.
69
-
70
- ```ts
71
- const ctx = await memorio.memory.context({
72
- tags: 'project',
73
- types: ['decision', 'preference'],
74
- minConfidence: 0.7,
75
- maxEntries: 10,
76
- scopes: ['local', 'durable']
77
- })
78
- ```
79
-
80
- Returns:
81
- ```ts
82
- Array<{
83
- key: string
84
- value: any
85
- type: MemoryType
86
- confidence: number
87
- scope: MemoryScope
88
- tags: string[]
89
- age: number // milliseconds since createdAt
90
- accessCount: number
91
- lastAccessedAt: number
92
- }>
93
- ```
94
-
95
- ### `memorio.memory.stats()`
96
-
97
- Returns usage statistics:
98
-
99
- ```ts
100
- {
101
- total: number
102
- byScope: Record<MemoryScope, number>
103
- byType: Partial<Record<MemoryType, number>>
104
- expired: number
105
- }
106
- ```
107
-
108
- ### `memorio.memory.forgetExpired()`
109
-
110
- Cleans all expired entries. Returns count removed.
111
-
112
- ### `memorio.memory.clear()`
113
-
114
- Wipes all memories and the index.
115
-
116
- ## Memory Entry Model
117
-
118
- ```ts
119
- interface MemoryEntry<T = any> {
120
- id: string
121
- key: string
122
- value: T
123
- type: 'fact' | 'preference' | 'decision' | 'task' | 'context'
124
- confidence: number
125
- scope: 'hot' | 'session' | 'local' | 'durable'
126
- ttl?: number | null
127
- tags: string[]
128
- source?: string
129
- status: 'active' | 'obsolete' | 'superseded'
130
- createdAt: number
131
- lastConfirmedAt: number
132
- supersededId?: string | null
133
- }
134
- ```
135
-
136
- ## Scopes
137
-
138
- | Scope | Storage | TTL | Cross-session | Size limit |
139
- |-------|---------|-----|---------------|------------|
140
- | `hot` | `state` proxy | ✅ | ❌ | ~5MB (RAM) |
141
- | `session` | `sessionStorage` | ✅ | Tab only | ~5MB |
142
- | `local` | `localStorage` | ✅ | ✅ | ~10MB |
143
- | `durable` | `IndexedDB` | ✅ | ✅ | ~1GB+ |
144
-
145
- Default scope is `local` for values ≤100KB, `durable` for larger values.
146
-
147
- ## Memory Lifecycle
148
-
149
- | Event | Behavior |
150
- |-------|----------|
151
- | `remember()` on existing key | Old entry → `superseded`, new entry → `active` |
152
- | Entry with TTL expires | Status → `obsolete` (cleaned by `forgetExpired()`) |
153
- | `recall()` expired entry | Returns `null` unless `includeObsolete: true` |
154
- | `update()` | Creates superseded copy + updated active entry |
155
- | `clear()` | Wipes all memories + index |
@@ -1,200 +0,0 @@
1
- # Observer - Memorio
2
-
3
- Observer lets you react to state changes. When a state key changes, your callback function runs.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install memorio
9
- ```
10
-
11
- ```javascript
12
- import 'memorio';
13
- ```
14
-
15
- ---
16
-
17
- ## Quick Examples
18
-
19
- ### Example 1: Basic Usage
20
-
21
- ```javascript
22
- observer('state.counter', (newValue) => {
23
- console.debug('Counter is now:', newValue);
24
- });
25
-
26
- state.counter = 1;
27
- // Output: "Counter is now: 1"
28
-
29
- state.counter = 5;
30
- // Output: "Counter is now: 5"
31
- ```
32
-
33
- ### Example 2: Intermediate
34
-
35
- ```javascript
36
- // Observer with old value
37
- observer('state.user', (newValue, oldValue) => {
38
- console.debug(`User changed from ${oldValue?.name} to ${newValue?.name}`);
39
- });
40
-
41
- state.user = { name: 'Mario' };
42
- // Output: "User changed from undefined to Mario"
43
-
44
- state.user = { name: 'Luigi' };
45
- // Output: "User changed from Mario to Luigi"
46
- ```
47
-
48
- ### Example 3: Advanced
49
-
50
- ```javascript
51
- // Multiple callbacks for same path
52
- observer('state.data', [handler1, handler2]);
53
-
54
- // List all observers
55
- console.debug(observer.list);
56
- // Output: [{ name: 'state.data', id: '...' }, ...]
57
-
58
- // Remove specific observer
59
- observer.remove('state.data');
60
-
61
- // Remove all observers
62
- observer.removeAll();
63
-
64
- // Check if observer exists
65
- if (observer.has('state.counter')) {
66
- console.debug('Observer exists for counter');
67
- }
68
- ```
69
-
70
- ---
71
-
72
- ## Direct Values (Vanilla JS)
73
-
74
- Observer supports direct state values, not just string paths:
75
-
76
- ```javascript
77
- // Direct value - no string needed!
78
- observer(state.counter, (newValue) => {
79
- console.debug('Counter:', newValue);
80
- });
81
-
82
- // Works with objects too
83
- observer(state.user, (newValue) => {
84
- console.debug('User:', newValue?.name);
85
- });
86
-
87
- // Multiple callbacks as array
88
- observer('state.data', [cb1, cb2, cb3]);
89
- ```
90
-
91
- ---
92
-
93
- ## API Reference
94
-
95
- ### observer(path, callback, option)
96
-
97
- | Parameter | Type | Description |
98
- |-----------|------|-------------|
99
- | `path` | `string \| object` | State path (e.g., `'state.counter'`) or direct state value |
100
- | `callback` | `function \| array` | Function(s) called on change. Can be a single function or array of functions |
101
- | `option` | `boolean` | Listen continuously (default: `true`) |
102
-
103
- ### Callback Parameters
104
-
105
- ```javascript
106
- observer('state.key', (newValue, oldValue) => {
107
- // newValue: the new value
108
- // oldValue: the previous value
109
- });
110
- ```
111
-
112
- ### Properties
113
-
114
- | Property | Type | Description |
115
- |----------|------|-------------|
116
- | `observer.list` | `Array` | Get all active observers |
117
-
118
- ### Methods
119
-
120
- | Method | Parameters | Description |
121
- |--------|------------|-------------|
122
- | `observer.remove(name)` | `string` | Remove observer for specific path |
123
- | `observer.removeAll()` | none | Remove all observers |
124
- | `observer.has(name)` | `string` | Check if observer exists for path (returns boolean) |
125
-
126
- ---
127
-
128
- ## React Integration
129
-
130
- ### With useState
131
-
132
- ```javascript
133
- const [count, setCount] = useState(0);
134
-
135
- observer('state.counter', () => {
136
- setCount(state.counter);
137
- });
138
- ```
139
-
140
- ### With useEffect
141
-
142
- ```javascript
143
- useEffect(() => {
144
- const handleChange = (newVal) => {
145
- console.debug('Changed:', newVal);
146
- };
147
-
148
- observer('state.data', handleChange);
149
-
150
- // Cleanup
151
- return () => observer.remove('state.data');
152
- }, []);
153
- ```
154
-
155
- ---
156
-
157
- ## How It Works
158
-
159
- Observer subscribes to state changes via the Proxy's set trap. When `state.key = value` is called:
160
- 1. The Proxy intercepts the set
161
- 2. Fires all callbacks registered for that path
162
- 3. Callbacks receive newValue and oldValue
163
-
164
- ---
165
-
166
- ## Best Practices
167
-
168
- 1. Clean up observers in React `useEffect` return
169
- 2. Use specific paths: `'state.user.name'` not `'state'`
170
- 3. Remove observers when components unmount
171
- 4. Use `observer.removeAll()` on page navigation
172
-
173
- ---
174
-
175
- ## Common Patterns
176
-
177
- ### Form Validation
178
-
179
- ```javascript
180
- observer('state.form.email', (email) => {
181
- const isValid = email.includes('@');
182
- state.form.isValid = isValid;
183
- });
184
- ```
185
-
186
- ### Analytics
187
-
188
- ```javascript
189
- observer('state.page', (page) => {
190
- analytics.track('page_view', { page });
191
- });
192
- ```
193
-
194
- ### Auto-save
195
-
196
- ```javascript
197
- observer('state.draft', (content) => {
198
- store.set('autosave', content);
199
- });
200
- ```