memorio 4.3.2 → 4.4.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.
- package/README.md +10 -4
- package/SUMMARY.md +2 -1
- package/index.cjs +155 -124
- package/index.js +153 -124
- package/llms.txt +16 -16
- package/markdown/CHANGELOG.md +1 -1
- package/markdown/DISPATCH.md +168 -0
- package/markdown/OBSERVER.md +33 -13
- package/markdown/USEOBSERVER.md +112 -13
- package/package.json +4 -7
- package/types/memorio.d.ts +3 -0
package/llms.txt
CHANGED
|
@@ -19,7 +19,7 @@ Memorio provides 6 storage modules plus utilities:
|
|
|
19
19
|
| `session` | sessionStorage | Dies with browser tab |
|
|
20
20
|
| `cache` | In-memory cache | Fastest read, no persistence |
|
|
21
21
|
| `idb` | IndexedDB | Structured, async, persistent (browser-only) |
|
|
22
|
-
| `observer` | Object watcher | Legacy
|
|
22
|
+
| `observer` | Object watcher | Legacy |
|
|
23
23
|
| `useObserver` | React hook | Auto-discovery of state paths |
|
|
24
24
|
|
|
25
25
|
## Quick Start
|
|
@@ -33,7 +33,7 @@ state.counter = 0
|
|
|
33
33
|
|
|
34
34
|
// Observe changes (React hook)
|
|
35
35
|
useObserver(
|
|
36
|
-
() => { console.
|
|
36
|
+
() => { console.debug('counter:', state.counter) },
|
|
37
37
|
[state.counter]
|
|
38
38
|
)
|
|
39
39
|
```
|
|
@@ -54,7 +54,7 @@ state.counter = 0
|
|
|
54
54
|
const name = state.user.name // 'Sara'
|
|
55
55
|
|
|
56
56
|
// List all keys
|
|
57
|
-
console.
|
|
57
|
+
console.debug(state.list) // ['user', 'items', 'counter']
|
|
58
58
|
|
|
59
59
|
// Remove one key
|
|
60
60
|
state.remove('items')
|
|
@@ -100,10 +100,10 @@ store.removeAll()
|
|
|
100
100
|
store.clearAll()
|
|
101
101
|
|
|
102
102
|
// Check size
|
|
103
|
-
console.
|
|
103
|
+
console.debug(store.size(), 'chars stored')
|
|
104
104
|
|
|
105
105
|
// Check if persistent (real localStorage vs memory fallback)
|
|
106
|
-
console.
|
|
106
|
+
console.debug(store.isPersistent) // true → real localStorage
|
|
107
107
|
|
|
108
108
|
// Estimate quota usage (returns [0, 0] for localStorage)
|
|
109
109
|
await store.quota() // [usage, quota] in KB
|
|
@@ -136,10 +136,10 @@ session.removeAll()
|
|
|
136
136
|
session.clearAll()
|
|
137
137
|
|
|
138
138
|
// Check size
|
|
139
|
-
console.
|
|
139
|
+
console.debug(session.size(), 'chars stored')
|
|
140
140
|
|
|
141
141
|
// Check if persistent
|
|
142
|
-
console.
|
|
142
|
+
console.debug(session.isPersistent)
|
|
143
143
|
```
|
|
144
144
|
|
|
145
145
|
### `cache` — In-Memory Cache
|
|
@@ -215,14 +215,14 @@ const [usage, quota] = await idb.db.quota()
|
|
|
215
215
|
|
|
216
216
|
**Note:** In Node.js/Deno, `idb` is disabled with a warning. Use `store` or `session` instead.
|
|
217
217
|
|
|
218
|
-
### `observer` — Object Watcher
|
|
218
|
+
### `observer` — Object Watcher
|
|
219
219
|
|
|
220
220
|
Legacy observer API. Use `useObserver` instead.
|
|
221
221
|
|
|
222
222
|
```javascript
|
|
223
223
|
// Listen to state changes
|
|
224
224
|
observer('state.user', (newVal, oldVal) => {
|
|
225
|
-
console.
|
|
225
|
+
console.debug('user changed:', newVal, oldVal)
|
|
226
226
|
})
|
|
227
227
|
|
|
228
228
|
// Toggle listening (no callback)
|
|
@@ -232,7 +232,7 @@ observer('state.counter')
|
|
|
232
232
|
observer.remove('state.user')
|
|
233
233
|
|
|
234
234
|
// List all observers
|
|
235
|
-
console.
|
|
235
|
+
console.debug(observer.list)
|
|
236
236
|
|
|
237
237
|
// Remove all observers
|
|
238
238
|
observer.removeAll()
|
|
@@ -251,12 +251,12 @@ function Counter() {
|
|
|
251
251
|
|
|
252
252
|
// Auto-discovery mode (no deps)
|
|
253
253
|
useObserver(() => {
|
|
254
|
-
console.
|
|
254
|
+
console.debug('counter:', state.counter)
|
|
255
255
|
}, state.counter)
|
|
256
256
|
|
|
257
257
|
// Explicit deps mode
|
|
258
258
|
useObserver(
|
|
259
|
-
() => { console.
|
|
259
|
+
() => { console.debug('user:', state.user) },
|
|
260
260
|
[state.user]
|
|
261
261
|
)
|
|
262
262
|
|
|
@@ -308,8 +308,8 @@ Track every state change with timestamps.
|
|
|
308
308
|
|
|
309
309
|
```javascript
|
|
310
310
|
// Configure logger
|
|
311
|
-
memorio.logger.configure({
|
|
312
|
-
enabled: true,
|
|
311
|
+
memorio.logger.configure({
|
|
312
|
+
enabled: true,
|
|
313
313
|
logToConsole: true,
|
|
314
314
|
modules: ['state', 'store', 'session', 'cache', 'idb']
|
|
315
315
|
})
|
|
@@ -345,7 +345,7 @@ memorio.createContext('tenant-name')
|
|
|
345
345
|
memorio.listContexts()
|
|
346
346
|
memorio.deleteContext('context-id')
|
|
347
347
|
memorio.isolate('tenant-name') // alias for createContext
|
|
348
|
-
```
|
|
348
|
+
```
|
|
349
349
|
|
|
350
350
|
## Cross-Platform Support
|
|
351
351
|
|
|
@@ -397,7 +397,7 @@ memorio.dispatch.set('custom:event', { detail: { data: 'value' } })
|
|
|
397
397
|
|
|
398
398
|
// Listen for an event
|
|
399
399
|
memorio.dispatch.listen('custom:event', (e) => {
|
|
400
|
-
console.
|
|
400
|
+
console.debug('Event triggered:', e.detail)
|
|
401
401
|
})
|
|
402
402
|
|
|
403
403
|
// Remove listener
|
package/markdown/CHANGELOG.md
CHANGED
|
@@ -56,7 +56,7 @@ All notable changes to this project will be documented in this file.
|
|
|
56
56
|
|
|
57
57
|
### 📝 Documentation Updates
|
|
58
58
|
|
|
59
|
-
- `docs/README.md`: replaced `console.
|
|
59
|
+
- `docs/README.md`: replaced `console.debug` with `console.debug` in usage examples; fixed `esbuild` badge → `tsup`
|
|
60
60
|
- `.github/CHANGELOG.md`: restructured with fix / security / changed sections
|
|
61
61
|
- `.github/HISTORY.md`: complete rewrite through v3.0.2
|
|
62
62
|
- `.github/SECURITY.md`: NIST/NSA standard + OWASP Top 10 mapping
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# Dispatch - Memorio
|
|
2
|
+
|
|
3
|
+
> ⚛️ **Vanilla JS**: This is for non-React applications. For React, use [`useObserver`](USEOBSERVER.md).
|
|
4
|
+
|
|
5
|
+
`memorio.dispatch` is an event system for vanilla JavaScript applications. It enables pub/sub patterns without React hooks.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install memorio
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
import 'memorio';
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Quick Examples
|
|
20
|
+
|
|
21
|
+
### Example 1: Basic Event Listening
|
|
22
|
+
|
|
23
|
+
```javascript
|
|
24
|
+
// Listen for an event
|
|
25
|
+
memorio.dispatch.listen('my:event', (event) => {
|
|
26
|
+
console.debug('Event triggered:', event.detail);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Trigger the event
|
|
30
|
+
memorio.dispatch.set('my:event', { detail: { data: 'Hello World' } });
|
|
31
|
+
// Output: "Event triggered: { data: 'Hello World' }"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Example 2: State Reactivity (Vanilla JS)
|
|
35
|
+
|
|
36
|
+
```javascript
|
|
37
|
+
// React to state changes without React
|
|
38
|
+
memorio.dispatch.listen('state.counter', (event) => {
|
|
39
|
+
console.debug('Counter is now:', event.detail);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Update state
|
|
43
|
+
state.counter = 1;
|
|
44
|
+
// Output: "Counter is now: 1"
|
|
45
|
+
|
|
46
|
+
state.counter = 5;
|
|
47
|
+
// Output: "Counter is now: 5"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Example 3: Remove Listener
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
// Remove a specific event listener
|
|
54
|
+
memorio.dispatch.remove('my:event');
|
|
55
|
+
|
|
56
|
+
// Or remove all listeners for state changes
|
|
57
|
+
memorio.dispatch.remove('state.user');
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## API Reference
|
|
63
|
+
|
|
64
|
+
### memorio.dispatch.set(name, value)
|
|
65
|
+
|
|
66
|
+
Dispatches a custom event with the specified name and value.
|
|
67
|
+
|
|
68
|
+
| Parameter | Type | Description |
|
|
69
|
+
|-----------|------|-------------|
|
|
70
|
+
| `name` | `string` | Event name (e.g., `'my:event'`, `'state.counter'`) |
|
|
71
|
+
| `value` | `object` | Object with `detail` property (default: `{}`) |
|
|
72
|
+
|
|
73
|
+
```javascript
|
|
74
|
+
memorio.dispatch.set('custom:event', { detail: { data: 'value' } });
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### memorio.dispatch.listen(name, callback)
|
|
78
|
+
|
|
79
|
+
Listens for the specified event and executes the callback when triggered.
|
|
80
|
+
|
|
81
|
+
| Parameter | Type | Description |
|
|
82
|
+
|-----------|------|-------------|
|
|
83
|
+
| `name` | `string` | Event name to listen for |
|
|
84
|
+
| `callback` | `function` | Function called with the event object |
|
|
85
|
+
|
|
86
|
+
```javascript
|
|
87
|
+
memorio.dispatch.listen('state.user', (event) => {
|
|
88
|
+
console.debug('User changed:', event.detail);
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### memorio.dispatch.remove(name)
|
|
93
|
+
|
|
94
|
+
Removes the event listener for the specified event name.
|
|
95
|
+
|
|
96
|
+
| Parameter | Type | Description |
|
|
97
|
+
|-----------|------|-------------|
|
|
98
|
+
| `name` | `string` | Event name to stop listening |
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
memorio.dispatch.remove('state.counter');
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Common Patterns
|
|
107
|
+
|
|
108
|
+
### Form Validation
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
memorio.dispatch.listen('state.form.email', (event) => {
|
|
112
|
+
const email = event.detail;
|
|
113
|
+
const isValid = email.includes('@');
|
|
114
|
+
state.form.isValid = isValid;
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Analytics Tracking
|
|
119
|
+
|
|
120
|
+
```javascript
|
|
121
|
+
memorio.dispatch.listen('state.page', (event) => {
|
|
122
|
+
const page = event.detail;
|
|
123
|
+
analytics.track('page_view', { page });
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Auto-save
|
|
128
|
+
|
|
129
|
+
```javascript
|
|
130
|
+
memorio.dispatch.listen('state.draft', (event) => {
|
|
131
|
+
const content = event.detail;
|
|
132
|
+
store.set('autosave', content);
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Multiple Listeners
|
|
137
|
+
|
|
138
|
+
```javascript
|
|
139
|
+
// Listen for multiple state changes
|
|
140
|
+
memorio.dispatch.listen('state.user', (e) => console.log('User:', e.detail));
|
|
141
|
+
memorio.dispatch.listen('state.settings', (e) => console.log('Settings:', e.detail));
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Migration from observer()
|
|
147
|
+
|
|
148
|
+
The `observer()` Replace it with `memorio.dispatch.listen()`:
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
observer('state.counter', (newValue) => {
|
|
152
|
+
console.debug('Counter:', newValue);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// NEW (recommended for vanilla JS)
|
|
156
|
+
memorio.dispatch.listen('state.counter', (event) => {
|
|
157
|
+
console.debug('Counter:', event.detail);
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Best Practices
|
|
164
|
+
|
|
165
|
+
1. Use specific event names: `'state.user.name'` not `'state'`
|
|
166
|
+
2. Clean up listeners when no longer needed with `memorio.dispatch.remove()`
|
|
167
|
+
3. Use `event.detail` to access the value
|
|
168
|
+
4. For React applications, use [`useObserver`](USEOBSERVER.md) instead
|
package/markdown/OBSERVER.md
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# Observer - Memorio
|
|
2
2
|
|
|
3
|
-
> ⚠️ **DEPRECATED**: This function is deprecated and will be removed in future versions. Please use [`useObserver`](USEOBSERVER.md) instead.
|
|
4
|
-
|
|
5
3
|
Observer lets you react to state changes. When a state key changes, your callback function runs.
|
|
6
4
|
|
|
7
5
|
## Installation
|
|
@@ -21,9 +19,6 @@ import 'memorio';
|
|
|
21
19
|
### Example 1: Basic Usage
|
|
22
20
|
|
|
23
21
|
```javascript
|
|
24
|
-
// Simple observer (DEPRECATED - use useObserver instead)
|
|
25
|
-
console.warn('observer() is deprecated. Please use useObserver() for React or memorio.dispatch for vanilla JS.');
|
|
26
|
-
|
|
27
22
|
observer('state.counter', (newValue) => {
|
|
28
23
|
console.debug('Counter is now:', newValue);
|
|
29
24
|
});
|
|
@@ -35,8 +30,6 @@ state.counter = 5;
|
|
|
35
30
|
// Output: "Counter is now: 5"
|
|
36
31
|
```
|
|
37
32
|
|
|
38
|
-
> **Note**: For new projects, use [`useObserver`](USEOBSERVER.md) for React or [`memorio.dispatch`](SUMMARY.md) for vanilla JS.
|
|
39
|
-
|
|
40
33
|
### Example 2: Intermediate
|
|
41
34
|
|
|
42
35
|
```javascript
|
|
@@ -55,9 +48,8 @@ state.user = { name: 'Luigi' };
|
|
|
55
48
|
### Example 3: Advanced
|
|
56
49
|
|
|
57
50
|
```javascript
|
|
58
|
-
// Multiple
|
|
59
|
-
|
|
60
|
-
const obs2 = observer('state.data', handler2);
|
|
51
|
+
// Multiple callbacks for same path
|
|
52
|
+
observer('state.data', [handler1, handler2]);
|
|
61
53
|
|
|
62
54
|
// List all observers
|
|
63
55
|
console.debug(observer.list);
|
|
@@ -68,18 +60,45 @@ observer.remove('state.data');
|
|
|
68
60
|
|
|
69
61
|
// Remove all observers
|
|
70
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]);
|
|
71
89
|
```
|
|
72
90
|
|
|
73
91
|
---
|
|
74
92
|
|
|
75
93
|
## API Reference
|
|
76
94
|
|
|
77
|
-
### observer(path, callback)
|
|
95
|
+
### observer(path, callback, option)
|
|
78
96
|
|
|
79
97
|
| Parameter | Type | Description |
|
|
80
98
|
|-----------|------|-------------|
|
|
81
|
-
| `path` | `string` | State path
|
|
82
|
-
| `callback` | `function` | Function called on change |
|
|
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`) |
|
|
83
102
|
|
|
84
103
|
### Callback Parameters
|
|
85
104
|
|
|
@@ -102,6 +121,7 @@ observer('state.key', (newValue, oldValue) => {
|
|
|
102
121
|
|--------|------------|-------------|
|
|
103
122
|
| `observer.remove(name)` | `string` | Remove observer for specific path |
|
|
104
123
|
| `observer.removeAll()` | none | Remove all observers |
|
|
124
|
+
| `observer.has(name)` | `string` | Check if observer exists for path (returns boolean) |
|
|
105
125
|
|
|
106
126
|
---
|
|
107
127
|
|
package/markdown/USEOBSERVER.md
CHANGED
|
@@ -24,6 +24,7 @@ import 'memorio';
|
|
|
24
24
|
import 'memorio';
|
|
25
25
|
|
|
26
26
|
function Counter() {
|
|
27
|
+
// Direct values work! ✅
|
|
27
28
|
useObserver(() => {
|
|
28
29
|
console.debug('Counter changed:', state.counter);
|
|
29
30
|
}, [state.counter]);
|
|
@@ -63,14 +64,23 @@ function UserProfile() {
|
|
|
63
64
|
### Example 3: Advanced
|
|
64
65
|
|
|
65
66
|
```javascript
|
|
66
|
-
// Multiple watchers with array
|
|
67
|
+
// Multiple watchers with array - works with direct values
|
|
67
68
|
function MultiWatch() {
|
|
68
69
|
useObserver(() => {
|
|
69
70
|
console.debug('A or B changed:', state.a, state.b);
|
|
70
|
-
}, [state.a, state.b]);
|
|
71
|
-
|
|
71
|
+
}, [state.a, state.b]); // Direct values work!
|
|
72
|
+
|
|
72
73
|
return <div>{state.a} - {state.b}</div>;
|
|
73
74
|
}
|
|
75
|
+
|
|
76
|
+
// With string path (for store)
|
|
77
|
+
function StoreWatcher() {
|
|
78
|
+
useObserver(() => {
|
|
79
|
+
console.debug('Store changed');
|
|
80
|
+
}, 'store.userPreferences');
|
|
81
|
+
|
|
82
|
+
return <div />;
|
|
83
|
+
}
|
|
74
84
|
```
|
|
75
85
|
// With string path (for store)
|
|
76
86
|
function StoreWatcher() {
|
|
@@ -91,15 +101,49 @@ function StoreWatcher() {
|
|
|
91
101
|
| Parameter | Type | Description |
|
|
92
102
|
| --------- | ---- | ----------- |
|
|
93
103
|
| `callback` | `function` | Function to run on change |
|
|
94
|
-
| `deps` | `function \| string \| array` | State path(s) to watch |
|
|
104
|
+
| `deps` | `function \| string \| array \| proxy` | State path(s) to watch. Supports: |
|
|
105
|
+
| | | - Direct values: `state.counter` |
|
|
106
|
+
| | | - String paths: `'state.counter'` |
|
|
107
|
+
| | | - Arrow functions: `() => state.counter` |
|
|
108
|
+
| | | - Arrays: `[state.a, state.b]` or `['state.a', 'state.b']` |
|
|
109
|
+
| | | - Optional chaining: `[state?.one]` |
|
|
110
|
+
|
|
111
|
+
### Primitive Values
|
|
112
|
+
|
|
113
|
+
Direct primitive values are now fully supported:
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
// Direct values work with primitives ✅
|
|
117
|
+
useObserver(() => { console.debug('changed') }, [state.counter])
|
|
118
|
+
|
|
119
|
+
// Arrays of primitives work ✅
|
|
120
|
+
useObserver(() => { console.log(state.a, state.b) }, [state.a, state.b])
|
|
121
|
+
|
|
122
|
+
// Optional chaining works ✅
|
|
123
|
+
useObserver(() => { console.log(state?.one) }, [state?.one])
|
|
124
|
+
|
|
125
|
+
// Strings still work ✅
|
|
126
|
+
useObserver(() => { console.debug('changed') }, ['state.counter'])
|
|
127
|
+
|
|
128
|
+
// Functions still work ✅
|
|
129
|
+
useObserver(() => { console.debug('changed') }, [() => state.counter])
|
|
130
|
+
```
|
|
95
131
|
|
|
96
132
|
### Callback Parameters
|
|
97
133
|
|
|
98
134
|
```javascript
|
|
135
|
+
// Single value (no array needed)
|
|
99
136
|
useObserver(
|
|
100
137
|
() => {
|
|
101
138
|
console.debug('Changed:', state.key);
|
|
102
|
-
},
|
|
139
|
+
}, state.key // Single value works!
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
// Array of values
|
|
143
|
+
useObserver(
|
|
144
|
+
() => {
|
|
145
|
+
console.debug('Changed:', state.key);
|
|
146
|
+
}, [state.key] // Array also works!
|
|
103
147
|
);
|
|
104
148
|
```
|
|
105
149
|
|
|
@@ -129,24 +173,79 @@ Returns a cleanup function:
|
|
|
129
173
|
|
|
130
174
|
## Common Patterns
|
|
131
175
|
|
|
132
|
-
### Sync with useState
|
|
176
|
+
### Sync with useState (Recommended for Primitives)
|
|
133
177
|
|
|
134
178
|
```javascript
|
|
135
|
-
function
|
|
136
|
-
|
|
179
|
+
function CounterComponent() {
|
|
180
|
+
// Sync memorio state with React state
|
|
181
|
+
const [counter, setCounter] = useState(state.counter)
|
|
182
|
+
|
|
183
|
+
// React useEffect works correctly with primitive values
|
|
184
|
+
useEffect(() => {
|
|
185
|
+
console.log('Counter changed:', counter)
|
|
186
|
+
}, [counter])
|
|
187
|
+
|
|
188
|
+
// Direct values now work with primitives!
|
|
189
|
+
useObserver(() => {
|
|
190
|
+
setCounter(state.counter)
|
|
191
|
+
}, [state.counter]) // ✅ Works now!
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<div>
|
|
195
|
+
<button onClick={() => { state.counter++ }}>Increment</button>
|
|
196
|
+
<span>{counter}</span>
|
|
197
|
+
</div>
|
|
198
|
+
)
|
|
199
|
+
}
|
|
200
|
+
```
|
|
137
201
|
|
|
138
|
-
|
|
139
|
-
setData(newVal);
|
|
140
|
-
}, [state.data]);
|
|
202
|
+
### Safe Access with Optional Chaining (Protection)
|
|
141
203
|
|
|
142
|
-
|
|
204
|
+
```javascript
|
|
205
|
+
// Optional chaining is supported - protects against errors
|
|
206
|
+
useObserver(() => {
|
|
207
|
+
if (test?.one) {
|
|
208
|
+
console.log(test.one)
|
|
209
|
+
}
|
|
210
|
+
}, [test?.one])
|
|
211
|
+
|
|
212
|
+
// Works with objects
|
|
213
|
+
function SafeComponent() {
|
|
214
|
+
const [test, setTest] = useState(state.test)
|
|
215
|
+
|
|
216
|
+
useEffect(() => {
|
|
217
|
+
if (test?.one) {
|
|
218
|
+
console.log('test.one:', test.one)
|
|
219
|
+
}
|
|
220
|
+
}, [test?.one])
|
|
221
|
+
|
|
222
|
+
useObserver(() => {
|
|
223
|
+
if (state.test?.one) {
|
|
224
|
+
setTest(state.test)
|
|
225
|
+
}
|
|
226
|
+
}, ['state.test.one'])
|
|
227
|
+
|
|
228
|
+
return <div>{test?.one || 'Loading...'}</div>
|
|
143
229
|
}
|
|
144
230
|
```
|
|
145
231
|
|
|
146
232
|
### Multiple Watchers
|
|
147
233
|
|
|
148
234
|
```javascript
|
|
149
|
-
|
|
235
|
+
// Watch multiple properties with strings
|
|
236
|
+
useObserver(() => {
|
|
237
|
+
console.log(state.a, state.b)
|
|
238
|
+
}, ['state.a', 'state.b'])
|
|
239
|
+
|
|
240
|
+
// Watch multiple properties with functions
|
|
241
|
+
useObserver(() => {
|
|
242
|
+
console.log(state.a, state.b)
|
|
243
|
+
}, [() => state.a, () => state.b])
|
|
244
|
+
|
|
245
|
+
// Watch with auto-discovery
|
|
246
|
+
useObserver(() => {
|
|
247
|
+
console.log(state.a, state.b) // Automatically tracks both
|
|
248
|
+
}, [])
|
|
150
249
|
```
|
|
151
250
|
|
|
152
251
|
---
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memorio",
|
|
3
3
|
"codeName": "memorio",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.4.0",
|
|
5
5
|
"description": "Memorio, State + Observer, Store and iDB for an easy life - Cross-platform compatible",
|
|
6
6
|
"main": "./index.cjs",
|
|
7
7
|
"browser": "./index.cjs",
|
|
@@ -55,14 +55,11 @@
|
|
|
55
55
|
"url": "https://dario.passariello.ca/",
|
|
56
56
|
"email": "dariopassariello@gmail.com"
|
|
57
57
|
},
|
|
58
|
-
"
|
|
59
|
-
"
|
|
58
|
+
"resolutions": {
|
|
59
|
+
"esbuild": "^0.25.0"
|
|
60
60
|
},
|
|
61
61
|
"overrides": {
|
|
62
|
-
"
|
|
63
|
-
},
|
|
64
|
-
"resolutions": {
|
|
65
|
-
"object-assign": "npm:@socketregistry/object-assign@^1"
|
|
62
|
+
"esbuild": "^0.25.0"
|
|
66
63
|
},
|
|
67
64
|
"exports": {
|
|
68
65
|
".": {
|
package/types/memorio.d.ts
CHANGED
|
@@ -29,6 +29,9 @@ interface _memorio {
|
|
|
29
29
|
_tracking?: boolean
|
|
30
30
|
_trackedPaths?: Set<string>
|
|
31
31
|
_locked?: boolean
|
|
32
|
+
_lastAccessedPath?: string
|
|
33
|
+
_stateVersion?: number
|
|
34
|
+
_propertyAccessLog?: string[]
|
|
32
35
|
// Platform detection
|
|
33
36
|
isBrowser: () => boolean
|
|
34
37
|
isNode: () => boolean
|