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.
- package/AGENTS.md +3 -3
- package/README.md +307 -359
- package/SECURITY.md +17 -1
- package/SUMMARY.md +59 -45
- package/adr/001-state-proxy-model.md +96 -0
- package/adr/002-observer-semantics.md +180 -0
- package/adr/003-deep-mutation-semantics.md +129 -0
- package/adr/004-array-mutation-semantics.md +128 -0
- package/adr/005-scheduler-contract.md +149 -0
- package/adr/006-context-isolation.md +92 -0
- package/adr/007-mutation-records.md +118 -0
- package/adr/008-transactions.md +106 -0
- package/adr/009-history-model.md +110 -0
- package/adr/README.md +46 -0
- package/adr/template.md +49 -0
- package/examples/basic.ts +115 -115
- package/examples/browser-vanilla.html +358 -358
- package/examples/cache.ts +72 -72
- package/examples/cross-platform-guards.ts +57 -57
- package/examples/history.ts +104 -0
- package/examples/idb.ts +109 -109
- package/examples/multi-tenant-context.ts +44 -44
- package/examples/node-server.ts +308 -308
- package/examples/observer.ts +60 -60
- package/examples/platform.ts +115 -115
- package/examples/react-app.tsx +362 -362
- package/examples/react-observer.tsx +63 -63
- package/examples/semantic-memory.ts +60 -60
- package/examples/session-advanced.ts +91 -91
- package/examples/sqlite-batched-writes.ts +57 -57
- package/examples/state-advanced.ts +89 -89
- package/examples/store-advanced.ts +117 -117
- package/examples/sync.ts +90 -0
- package/examples/typed-and-schema.ts +102 -100
- package/examples/useObserver.tsx +140 -141
- package/global.cjs +4594 -0
- package/global.d.ts +8 -0
- package/global.js +4532 -0
- package/index.cjs +700 -678
- package/index.d.ts +1 -0
- package/index.js +680 -677
- package/llms.txt +72 -4
- package/markdown/AUDIT-REPORT.md +135 -0
- package/markdown/CACHE.md +100 -0
- package/markdown/CHANGELOG.md +243 -0
- package/markdown/DEVTOOLS.md +129 -0
- package/markdown/DISPATCH.md +177 -0
- package/markdown/HISTORY.md +199 -0
- package/markdown/IDB.md +178 -0
- package/markdown/IMPORT.md +153 -0
- package/markdown/INSPECT.md +123 -0
- package/markdown/LOGGER.md +154 -0
- package/markdown/MEMORY-ATTACHMENT.md +96 -0
- package/markdown/MEMORY.md +162 -0
- package/markdown/OBSERVER.md +209 -0
- package/markdown/PLATFORM.md +271 -0
- package/markdown/PROJECT.md +311 -0
- package/markdown/SCHEMA.md +176 -0
- package/markdown/SECURITY.md +330 -0
- package/markdown/SESSION.md +165 -0
- package/markdown/SQLITE.md +190 -0
- package/markdown/STATE.md +160 -0
- package/markdown/STORE.md +171 -0
- package/markdown/SYNC.md +319 -0
- package/markdown/TYPED.md +165 -0
- package/markdown/USEOBSERVER.md +257 -0
- package/modules/redux.cjs +320 -167
- package/modules/redux.cjs.map +1 -1
- package/modules/redux.js +320 -167
- package/modules/redux.js.map +1 -1
- package/package.json +13 -3
- package/types/env.d.ts +19 -9
- package/types/exports.d.ts +20 -0
- package/types/history.d.ts +13 -1
- package/types/memorio.d.ts +17 -5
- package/types/mutation.d.ts +75 -0
|
@@ -1,89 +1,89 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Memorio State Advanced Example
|
|
3
|
-
*
|
|
4
|
-
* This example shows advanced state features: locking, path tracking, and nesting.
|
|
5
|
-
*
|
|
6
|
-
* Run: npx ts-node examples/state-advanced.ts
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import 'memorio'
|
|
10
|
-
|
|
11
|
-
// ============================================
|
|
12
|
-
// NESTED OBJECTS
|
|
13
|
-
// ============================================
|
|
14
|
-
|
|
15
|
-
// Create nested state
|
|
16
|
-
state.user = {
|
|
17
|
-
name: 'Mario',
|
|
18
|
-
profile: {
|
|
19
|
-
email: 'mario@example.com',
|
|
20
|
-
settings: {
|
|
21
|
-
theme: 'dark',
|
|
22
|
-
notifications: true
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Access nested values
|
|
28
|
-
console.debug('User name:', state.user.name)
|
|
29
|
-
console.debug('Email:', state.user.profile.email)
|
|
30
|
-
console.debug('Theme:', state.user.profile.settings.theme)
|
|
31
|
-
|
|
32
|
-
// ============================================
|
|
33
|
-
// ARRAYS
|
|
34
|
-
// ============================================
|
|
35
|
-
|
|
36
|
-
// State arrays work like regular arrays
|
|
37
|
-
state.items = [1, 2, 3]
|
|
38
|
-
state.items.push(4)
|
|
39
|
-
console.debug('Items:', state.items) // [1, 2, 3, 4]
|
|
40
|
-
|
|
41
|
-
state.users = [
|
|
42
|
-
{ name: 'Mario', id: 1 },
|
|
43
|
-
{ name: 'Luigi', id: 2 }
|
|
44
|
-
]
|
|
45
|
-
state.users.push({ name: 'Peach', id: 3 })
|
|
46
|
-
console.debug('Users:', state.users)
|
|
47
|
-
|
|
48
|
-
// ============================================
|
|
49
|
-
// LOCKING STATE
|
|
50
|
-
// ============================================
|
|
51
|
-
|
|
52
|
-
// Lock a value to prevent modifications
|
|
53
|
-
state.config = { maxUsers: 100, timeout: 30 }
|
|
54
|
-
state.config.lock()
|
|
55
|
-
|
|
56
|
-
// This will fail:
|
|
57
|
-
// state.config.maxUsers = 200 // Error: state 'config' is locked
|
|
58
|
-
|
|
59
|
-
console.debug('Config locked:', state.config)
|
|
60
|
-
|
|
61
|
-
// ============================================
|
|
62
|
-
// PATH TRACKING
|
|
63
|
-
// ============================================
|
|
64
|
-
|
|
65
|
-
// Get path information
|
|
66
|
-
console.debug('Path:', state.user.__path) // "state.user"
|
|
67
|
-
|
|
68
|
-
// Use path tracker for debugging
|
|
69
|
-
const path = state.user.profile
|
|
70
|
-
console.debug('Profile path:', path.email.toString()) // "state.user.profile.email"
|
|
71
|
-
|
|
72
|
-
// ============================================
|
|
73
|
-
// LIST ALL STATES
|
|
74
|
-
// ============================================
|
|
75
|
-
|
|
76
|
-
// Get all current state keys
|
|
77
|
-
console.debug('All states:', state.list)
|
|
78
|
-
|
|
79
|
-
// ============================================
|
|
80
|
-
// REMOVE STATE
|
|
81
|
-
// ============================================
|
|
82
|
-
|
|
83
|
-
// Remove specific state
|
|
84
|
-
state.remove('items')
|
|
85
|
-
|
|
86
|
-
// Remove all states
|
|
87
|
-
// state.removeAll()
|
|
88
|
-
|
|
89
|
-
console.debug('State advanced example complete!')
|
|
1
|
+
/**
|
|
2
|
+
* Memorio State Advanced Example
|
|
3
|
+
*
|
|
4
|
+
* This example shows advanced state features: locking, path tracking, and nesting.
|
|
5
|
+
*
|
|
6
|
+
* Run: npx ts-node examples/state-advanced.ts
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { state } from 'memorio'
|
|
10
|
+
|
|
11
|
+
// ============================================
|
|
12
|
+
// NESTED OBJECTS
|
|
13
|
+
// ============================================
|
|
14
|
+
|
|
15
|
+
// Create nested state
|
|
16
|
+
state.user = {
|
|
17
|
+
name: 'Mario',
|
|
18
|
+
profile: {
|
|
19
|
+
email: 'mario@example.com',
|
|
20
|
+
settings: {
|
|
21
|
+
theme: 'dark',
|
|
22
|
+
notifications: true
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Access nested values
|
|
28
|
+
console.debug('User name:', state.user.name)
|
|
29
|
+
console.debug('Email:', state.user.profile.email)
|
|
30
|
+
console.debug('Theme:', state.user.profile.settings.theme)
|
|
31
|
+
|
|
32
|
+
// ============================================
|
|
33
|
+
// ARRAYS
|
|
34
|
+
// ============================================
|
|
35
|
+
|
|
36
|
+
// State arrays work like regular arrays
|
|
37
|
+
state.items = [1, 2, 3]
|
|
38
|
+
state.items.push(4)
|
|
39
|
+
console.debug('Items:', state.items) // [1, 2, 3, 4]
|
|
40
|
+
|
|
41
|
+
state.users = [
|
|
42
|
+
{ name: 'Mario', id: 1 },
|
|
43
|
+
{ name: 'Luigi', id: 2 }
|
|
44
|
+
]
|
|
45
|
+
state.users.push({ name: 'Peach', id: 3 })
|
|
46
|
+
console.debug('Users:', state.users)
|
|
47
|
+
|
|
48
|
+
// ============================================
|
|
49
|
+
// LOCKING STATE
|
|
50
|
+
// ============================================
|
|
51
|
+
|
|
52
|
+
// Lock a value to prevent modifications
|
|
53
|
+
state.config = { maxUsers: 100, timeout: 30 }
|
|
54
|
+
state.config.lock()
|
|
55
|
+
|
|
56
|
+
// This will fail:
|
|
57
|
+
// state.config.maxUsers = 200 // Error: state 'config' is locked
|
|
58
|
+
|
|
59
|
+
console.debug('Config locked:', state.config)
|
|
60
|
+
|
|
61
|
+
// ============================================
|
|
62
|
+
// PATH TRACKING
|
|
63
|
+
// ============================================
|
|
64
|
+
|
|
65
|
+
// Get path information
|
|
66
|
+
console.debug('Path:', state.user.__path) // "state.user"
|
|
67
|
+
|
|
68
|
+
// Use path tracker for debugging
|
|
69
|
+
const path = state.user.profile
|
|
70
|
+
console.debug('Profile path:', path.email.toString()) // "state.user.profile.email"
|
|
71
|
+
|
|
72
|
+
// ============================================
|
|
73
|
+
// LIST ALL STATES
|
|
74
|
+
// ============================================
|
|
75
|
+
|
|
76
|
+
// Get all current state keys
|
|
77
|
+
console.debug('All states:', state.list)
|
|
78
|
+
|
|
79
|
+
// ============================================
|
|
80
|
+
// REMOVE STATE
|
|
81
|
+
// ============================================
|
|
82
|
+
|
|
83
|
+
// Remove specific state
|
|
84
|
+
state.remove('items')
|
|
85
|
+
|
|
86
|
+
// Remove all states
|
|
87
|
+
// state.removeAll()
|
|
88
|
+
|
|
89
|
+
console.debug('State advanced example complete!')
|
|
@@ -1,117 +1,117 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Memorio Store Advanced Example
|
|
3
|
-
*
|
|
4
|
-
* This example shows advanced store (localStorage) operations.
|
|
5
|
-
*
|
|
6
|
-
* Run: npx ts-node examples/store-advanced.ts
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import 'memorio'
|
|
10
|
-
|
|
11
|
-
// ============================================
|
|
12
|
-
// CHECK PERSISTENCE
|
|
13
|
-
// ============================================
|
|
14
|
-
|
|
15
|
-
console.debug('=== Store Persistence Check ===')
|
|
16
|
-
console.debug('Is persistent (survives restart):', store.isPersistent)
|
|
17
|
-
// In browser: true (localStorage)
|
|
18
|
-
// In Node.js/Deno: false (memory fallback)
|
|
19
|
-
|
|
20
|
-
if (!store.isPersistent) {
|
|
21
|
-
console.debug('⚠️ Warning: Using in-memory storage. Data will be lost on restart!')
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// ============================================
|
|
25
|
-
// PERSIST USER PREFERENCES
|
|
26
|
-
// ============================================
|
|
27
|
-
|
|
28
|
-
// Save user preferences
|
|
29
|
-
store.set('preferences', {
|
|
30
|
-
theme: 'dark',
|
|
31
|
-
language: 'en',
|
|
32
|
-
notifications: true,
|
|
33
|
-
fontSize: 16
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
// ============================================
|
|
37
|
-
// CHECK AND LOAD PREFERENCES
|
|
38
|
-
// ============================================
|
|
39
|
-
|
|
40
|
-
const savedPrefs = store.get('preferences')
|
|
41
|
-
if (savedPrefs) {
|
|
42
|
-
console.debug('Loaded preferences:', savedPrefs)
|
|
43
|
-
} else {
|
|
44
|
-
console.debug('No preferences found, using defaults')
|
|
45
|
-
store.set('preferences', { theme: 'light', language: 'en' })
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// ============================================
|
|
49
|
-
// STORAGE QUOTA
|
|
50
|
-
// ============================================
|
|
51
|
-
|
|
52
|
-
// Get storage size
|
|
53
|
-
const currentSize = store.size()
|
|
54
|
-
console.debug('Current storage size:', currentSize, 'kilobytes')
|
|
55
|
-
|
|
56
|
-
// ============================================
|
|
57
|
-
// ALIAS METHODS
|
|
58
|
-
// ============================================
|
|
59
|
-
|
|
60
|
-
// store.delete() is alias for store.remove()
|
|
61
|
-
store.set('temp', 'value')
|
|
62
|
-
store.delete('temp')
|
|
63
|
-
|
|
64
|
-
// store.clearAll() is alias for store.removeAll()
|
|
65
|
-
// store.clearAll()
|
|
66
|
-
|
|
67
|
-
// ============================================
|
|
68
|
-
// ERROR HANDLING
|
|
69
|
-
// ============================================
|
|
70
|
-
|
|
71
|
-
// Try-catch for large data
|
|
72
|
-
try {
|
|
73
|
-
// Store large data
|
|
74
|
-
const largeData = {
|
|
75
|
-
items: Array(1000).fill(null).map((_, i) => ({ id: i, data: 'x'.repeat(100) }))
|
|
76
|
-
}
|
|
77
|
-
store.set('largeData', largeData)
|
|
78
|
-
console.debug('Large data stored successfully')
|
|
79
|
-
} catch (error) {
|
|
80
|
-
console.error('Storage full:', error)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// ============================================
|
|
84
|
-
// DATA SERIALIZATION
|
|
85
|
-
// ============================================
|
|
86
|
-
|
|
87
|
-
// Store supports all JSON-serializable types
|
|
88
|
-
store.set('string', 'hello')
|
|
89
|
-
store.set('number', 42)
|
|
90
|
-
store.set('boolean', true)
|
|
91
|
-
store.set('array', [1, 2, 3])
|
|
92
|
-
store.set('object', { nested: { value: 'deep' } })
|
|
93
|
-
store.set('null', null)
|
|
94
|
-
|
|
95
|
-
// Functions are not supported (logged as error)
|
|
96
|
-
store.set('function', () => { }) // logs: "It's not secure to store functions."
|
|
97
|
-
|
|
98
|
-
// ============================================
|
|
99
|
-
// PRACTICAL EXAMPLE: APP STATE
|
|
100
|
-
// ============================================
|
|
101
|
-
|
|
102
|
-
// Save app state
|
|
103
|
-
const appState = {
|
|
104
|
-
lastPage: '/dashboard',
|
|
105
|
-
sidebarOpen: true,
|
|
106
|
-
recentFiles: ['file1.txt', 'file2.pdf'],
|
|
107
|
-
lastSaved: Date.now()
|
|
108
|
-
}
|
|
109
|
-
store.set('appState', appState)
|
|
110
|
-
|
|
111
|
-
// Load on next visit
|
|
112
|
-
const restored = store.get('appState')
|
|
113
|
-
if (restored) {
|
|
114
|
-
console.debug('Restored app state:', restored.lastPage)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
console.debug('Store advanced example complete!')
|
|
1
|
+
/**
|
|
2
|
+
* Memorio Store Advanced Example
|
|
3
|
+
*
|
|
4
|
+
* This example shows advanced store (localStorage) operations.
|
|
5
|
+
*
|
|
6
|
+
* Run: npx ts-node examples/store-advanced.ts
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { store } from 'memorio'
|
|
10
|
+
|
|
11
|
+
// ============================================
|
|
12
|
+
// CHECK PERSISTENCE
|
|
13
|
+
// ============================================
|
|
14
|
+
|
|
15
|
+
console.debug('=== Store Persistence Check ===')
|
|
16
|
+
console.debug('Is persistent (survives restart):', store.isPersistent)
|
|
17
|
+
// In browser: true (localStorage)
|
|
18
|
+
// In Node.js/Deno: false (memory fallback)
|
|
19
|
+
|
|
20
|
+
if (!store.isPersistent) {
|
|
21
|
+
console.debug('⚠️ Warning: Using in-memory storage. Data will be lost on restart!')
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ============================================
|
|
25
|
+
// PERSIST USER PREFERENCES
|
|
26
|
+
// ============================================
|
|
27
|
+
|
|
28
|
+
// Save user preferences
|
|
29
|
+
store.set('preferences', {
|
|
30
|
+
theme: 'dark',
|
|
31
|
+
language: 'en',
|
|
32
|
+
notifications: true,
|
|
33
|
+
fontSize: 16
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
// ============================================
|
|
37
|
+
// CHECK AND LOAD PREFERENCES
|
|
38
|
+
// ============================================
|
|
39
|
+
|
|
40
|
+
const savedPrefs = store.get('preferences')
|
|
41
|
+
if (savedPrefs) {
|
|
42
|
+
console.debug('Loaded preferences:', savedPrefs)
|
|
43
|
+
} else {
|
|
44
|
+
console.debug('No preferences found, using defaults')
|
|
45
|
+
store.set('preferences', { theme: 'light', language: 'en' })
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ============================================
|
|
49
|
+
// STORAGE QUOTA
|
|
50
|
+
// ============================================
|
|
51
|
+
|
|
52
|
+
// Get storage size
|
|
53
|
+
const currentSize = store.size()
|
|
54
|
+
console.debug('Current storage size:', currentSize, 'kilobytes')
|
|
55
|
+
|
|
56
|
+
// ============================================
|
|
57
|
+
// ALIAS METHODS
|
|
58
|
+
// ============================================
|
|
59
|
+
|
|
60
|
+
// store.delete() is alias for store.remove()
|
|
61
|
+
store.set('temp', 'value')
|
|
62
|
+
store.delete('temp')
|
|
63
|
+
|
|
64
|
+
// store.clearAll() is alias for store.removeAll()
|
|
65
|
+
// store.clearAll()
|
|
66
|
+
|
|
67
|
+
// ============================================
|
|
68
|
+
// ERROR HANDLING
|
|
69
|
+
// ============================================
|
|
70
|
+
|
|
71
|
+
// Try-catch for large data
|
|
72
|
+
try {
|
|
73
|
+
// Store large data
|
|
74
|
+
const largeData = {
|
|
75
|
+
items: Array(1000).fill(null).map((_, i) => ({ id: i, data: 'x'.repeat(100) }))
|
|
76
|
+
}
|
|
77
|
+
store.set('largeData', largeData)
|
|
78
|
+
console.debug('Large data stored successfully')
|
|
79
|
+
} catch (error) {
|
|
80
|
+
console.error('Storage full:', error)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ============================================
|
|
84
|
+
// DATA SERIALIZATION
|
|
85
|
+
// ============================================
|
|
86
|
+
|
|
87
|
+
// Store supports all JSON-serializable types
|
|
88
|
+
store.set('string', 'hello')
|
|
89
|
+
store.set('number', 42)
|
|
90
|
+
store.set('boolean', true)
|
|
91
|
+
store.set('array', [1, 2, 3])
|
|
92
|
+
store.set('object', { nested: { value: 'deep' } })
|
|
93
|
+
store.set('null', null)
|
|
94
|
+
|
|
95
|
+
// Functions are not supported (logged as error)
|
|
96
|
+
store.set('function', () => { }) // logs: "It's not secure to store functions."
|
|
97
|
+
|
|
98
|
+
// ============================================
|
|
99
|
+
// PRACTICAL EXAMPLE: APP STATE
|
|
100
|
+
// ============================================
|
|
101
|
+
|
|
102
|
+
// Save app state
|
|
103
|
+
const appState = {
|
|
104
|
+
lastPage: '/dashboard',
|
|
105
|
+
sidebarOpen: true,
|
|
106
|
+
recentFiles: ['file1.txt', 'file2.pdf'],
|
|
107
|
+
lastSaved: Date.now()
|
|
108
|
+
}
|
|
109
|
+
store.set('appState', appState)
|
|
110
|
+
|
|
111
|
+
// Load on next visit
|
|
112
|
+
const restored = store.get('appState')
|
|
113
|
+
if (restored) {
|
|
114
|
+
console.debug('Restored app state:', restored.lastPage)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
console.debug('Store advanced example complete!')
|
package/examples/sync.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sync.ts
|
|
3
|
+
*
|
|
4
|
+
* Scenario: an app using `memorio.memory` that wants to survive being
|
|
5
|
+
* offline (data is born local, in the journal, and always readable) and
|
|
6
|
+
* mirror itself to a backend when a connection is available.
|
|
7
|
+
*
|
|
8
|
+
* The cloud is a transport/persistence provider here, never the source of
|
|
9
|
+
* truth - sync mirrors the local journal, it doesn't replace it. Provide
|
|
10
|
+
* your own `SyncProvider`; memorio doesn't ship one.
|
|
11
|
+
*/
|
|
12
|
+
import { memorio } from 'memorio'
|
|
13
|
+
|
|
14
|
+
interface MemoryEntry {
|
|
15
|
+
key: string
|
|
16
|
+
value: unknown
|
|
17
|
+
confidence?: number
|
|
18
|
+
source?: string
|
|
19
|
+
scope?: 'device' | 'user' | 'shared'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface SyncProvider {
|
|
23
|
+
push(ops: MemoryEntry[]): Promise<{ synced: string[]; conflicts?: string[]; error?: string }>
|
|
24
|
+
pull?(since?: number): Promise<MemoryEntry[]>
|
|
25
|
+
resolve?(op: MemoryEntry): Promise<'local' | 'remote' | 'merge'>
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const backendProvider: SyncProvider = {
|
|
29
|
+
push: ops =>
|
|
30
|
+
fetch('/api/sync', {
|
|
31
|
+
method: 'POST',
|
|
32
|
+
body: JSON.stringify(ops),
|
|
33
|
+
headers: { 'Content-Type': 'application/json' }
|
|
34
|
+
}).then(r => r.json()),
|
|
35
|
+
|
|
36
|
+
pull: since => fetch(`/api/sync?since=${since ?? 0}`).then(r => r.json()),
|
|
37
|
+
|
|
38
|
+
// Higher-confidence entry wins locally; for 'shared' scope the provider
|
|
39
|
+
// (i.e. your backend) makes the final call instead.
|
|
40
|
+
resolve: async op => (op.confidence ?? 0) >= 0.8 ? 'local' : 'remote'
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export async function configureSync(namespace: string) {
|
|
44
|
+
// `scope: 'device'` data never syncs (sticky to this device) - only
|
|
45
|
+
// 'user' and 'shared' scoped entries flow through the provider below.
|
|
46
|
+
memorio.memory.configure({
|
|
47
|
+
namespace, // e.g. `user:123:device:abc` - partitions the local journal
|
|
48
|
+
provider: backendProvider,
|
|
49
|
+
auto: true // auto-replay the journal on focus/online (default: true)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
await memorio.memory.ready
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function rememberAndSync(key: string, value: unknown) {
|
|
56
|
+
// Local-first: this resolves immediately from the local store, no
|
|
57
|
+
// network round-trip required.
|
|
58
|
+
await memorio.memory.remember(key, value, { scope: 'user', source: 'app' })
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// The journal: the durable op log that drives cloud reconciliation
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
|
|
65
|
+
export async function inspectPendingOps() {
|
|
66
|
+
const pending = await memorio.memory.journal.pending()
|
|
67
|
+
console.debug('Operations waiting to sync:', pending)
|
|
68
|
+
return pending
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export async function forceReplay() {
|
|
72
|
+
// Pushes pending() to the provider, marks synced entries, and pulls if
|
|
73
|
+
// the provider implements it. Normally triggered automatically (`auto:
|
|
74
|
+
// true`) on focus/online - call this manually to sync on demand instead.
|
|
75
|
+
const ack = await memorio.memory.journal.replay()
|
|
76
|
+
console.debug('Sync result:', ack)
|
|
77
|
+
return ack
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export async function resetJournal() {
|
|
81
|
+
// Wipes the current namespace's journal only - does not touch the
|
|
82
|
+
// memory entries themselves, just the pending sync log.
|
|
83
|
+
await memorio.memory.journal.clear()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Usage:
|
|
87
|
+
// await configureSync('user:123:device:abc')
|
|
88
|
+
// await rememberAndSync('user.language', 'Italian')
|
|
89
|
+
// await inspectPendingOps()
|
|
90
|
+
// await forceReplay()
|