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.
package/markdown/STATE.md DELETED
@@ -1,153 +0,0 @@
1
- # State - Memorio
2
-
3
- > ✅ **Universal**: Works in Browser, Node.js, Deno, and Edge Workers
4
-
5
- State is a reactive global state manager using JavaScript Proxies. It's simple, powerful, and requires no setup. Data persists only in memory during the session.
6
-
7
- ## Installation
8
-
9
- ```bash
10
- npm install memorio
11
- ```
12
-
13
- ```javascript
14
- import 'memorio';
15
- ```
16
-
17
- That's it. `state` is now global.
18
-
19
- > **Classic `import`**: `state` is also a named export.
20
- > `import { state } from 'memorio'` returns the exact same proxy as `globalThis.state`.
21
-
22
- ---
23
-
24
- ## Quick Examples
25
-
26
- ### Example 1: Basic Usage
27
-
28
- ```javascript
29
- // Set a value
30
- state.name = 'Mario';
31
- state.age = 25;
32
-
33
- // Get a value
34
- console.debug(state.name); // "Mario"
35
-
36
- // Simple object
37
- state.user = { name: 'Luigi', level: 1 };
38
- ```
39
-
40
- ### Example 2: Intermediate
41
-
42
- ```javascript
43
- // Array operations
44
- state.items = [1, 2, 3];
45
- state.items.push(4);
46
- console.debug(state.items); // [1, 2, 3, 4]
47
-
48
- // Nested objects
49
- state.config = { theme: 'dark', lang: 'en' };
50
- state.config.theme = 'light';
51
-
52
- // List all states
53
- console.debug(state.list);
54
- ```
55
-
56
- ### Example 3: Advanced
57
-
58
- ```javascript
59
- // Lock state to prevent modifications
60
- state.frozenConfig = { maxUsers: 100 };
61
- state.frozenConfig.lock();
62
- // Now state.frozenConfig cannot be modified
63
-
64
- // Path tracking
65
- const path = state.user.path;
66
- console.debug(path.name); // "user"
67
- console.debug(path.profile.name); // "user.profile"
68
-
69
- // Get full path as string
70
- console.debug(state.user.__path); // "state.user"
71
-
72
- // Protected keys (internal use)
73
- console.debug(protect); // Array of protected keys
74
- ```
75
-
76
- ---
77
-
78
- ## API Reference
79
-
80
- ### Properties
81
-
82
- | Property | Type | Description |
83
- |----------|------|-------------|
84
- | `state.list` | Array | Get all current state keys (deep copy) |
85
- | `state.path` | Object | Get path tracker for current location |
86
- | `state.__path` | string | Get full path as string |
87
-
88
- ### Methods
89
-
90
- | Method | Parameters | Description |
91
- |--------|------------|-------------|
92
- | `state.remove(key)` | `key: string` | Remove a specific state |
93
- | `state.removeAll()` | none | Clear all states |
94
-
95
- ### Lock
96
-
97
- ```javascript
98
- // Lock an object or array
99
- state.myArray = [1, 2, 3];
100
- state.myArray.lock();
101
-
102
- // Now any modification will fail
103
- state.myArray.push(4); // Error: state 'myArray' is locked
104
- ```
105
-
106
- ---
107
-
108
- ## How It Works
109
-
110
- Memorio uses JavaScript `Proxy` to intercept get/set operations on the global `state` object. This allows:
111
-
112
- 1. **Reactivity** - Any change can trigger observers
113
- 2. **Nested objects** - Deep path tracking
114
- 3. **Type safety** - Full TypeScript support
115
-
116
- ---
117
-
118
- ## Platform Notes
119
-
120
- | Platform | Support | Notes |
121
- |----------|---------|-------|
122
- | Browser | ✅ Full | In-memory, lost on refresh |
123
- | Node.js | ✅ Full | In-memory, lost on restart |
124
- | Deno | ✅ Full | In-memory, lost on restart |
125
- | Edge Workers | ✅ Full | In-memory, lost on function cold start |
126
-
127
- **Note**: In server environments (Node.js/Deno), use `memorio.createContext()` for request isolation.
128
-
129
- ---
130
-
131
- ## Best Practices
132
-
133
- 1. Use descriptive keys: `state.userProfile` not `state.up`
134
- 2. Group related data: `state.cart.items` not `state.cartItems`
135
- 3. Lock static config: `state.appConfig.lock()`
136
- 4. Clean up on logout: `state.removeAll()`
137
- 5. Use path tracking for debugging: `state.myData.__path`
138
-
139
- ---
140
-
141
- ## Common Errors
142
-
143
- ```javascript
144
- // Error: protected key
145
- state._internal = 'value';
146
- // Output: "key _internal is protected"
147
-
148
- // Error: locked state
149
- state.locked = { x: 1 };
150
- state.locked.lock();
151
- state.locked.x = 2;
152
- // Output: "Error: state 'locked' is locked"
153
- ```
package/markdown/STORE.md DELETED
@@ -1,164 +0,0 @@
1
- # Store - Memorio
2
-
3
- > 🖥️ **Browser & Edge**: Uses localStorage for persistence
4
- > ⚙️ **Node.js/Deno**: Falls back to in-memory storage (not persistent)
5
-
6
- Store provides persistent localStorage management with a simple API. Data survives page refreshes and browser restarts.
7
-
8
- ## Installation
9
-
10
- ```bash
11
- npm install memorio
12
- ```
13
-
14
- ```javascript
15
- import 'memorio';
16
- ```
17
-
18
- > **Classic `import`**: `store` is also a named export.
19
- > `import { store } from 'memorio'` returns the exact same instance as `globalThis.store`.
20
-
21
- ---
22
-
23
- ## Quick Examples
24
-
25
- ### Example 1: Basic Usage
26
-
27
- ```javascript
28
- // Save data
29
- store.set('username', 'Mario');
30
- store.set('score', 1500);
31
-
32
- // Read data
33
- console.debug(store.get('username')); // "Mario"
34
- console.debug(store.get('score')); // 1500
35
-
36
- // Check if using real persistence
37
- console.debug(store.isPersistent); // true in browser, false in Node.js/Deno
38
- ```
39
-
40
- ### Example 2: Intermediate
41
-
42
- ```javascript
43
- // Store objects
44
- store.set('user', { name: 'Luigi', level: 5 });
45
- const user = store.get('user');
46
- console.debug(user.name); // "Luigi"
47
-
48
- // Remove single item
49
- store.remove('username');
50
-
51
- // Check size
52
- const totalSize = store.size();
53
- console.debug(`${totalSize} bytes`);
54
- ```
55
-
56
- ### Example 3: Advanced
57
-
58
- ```javascript
59
- // Get storage quota (returns Promise<[usage, quota]> in KB)
60
- const [used, total] = await store.quota();
61
- console.debug(`Using ${used} out of ${total} KB`);
62
-
63
- // Get total size in characters
64
- const size = store.size();
65
- console.debug(`${size} bytes`);
66
-
67
- // Clear all data
68
- store.removeAll();
69
- // or use alias
70
- store.clearAll();
71
-
72
- // Handle errors gracefully
73
- try {
74
- store.set('largeData', hugeObject);
75
- } catch (err) {
76
- console.error('Storage full:', err);
77
- }
78
- ```
79
-
80
- ---
81
-
82
- ## API Reference
83
-
84
- ### Methods
85
-
86
- | Method | Parameters | Returns | Description |
87
- |--------|------------|---------|-------------|
88
- | `store.get(name)` | `name: string` | `any` | Get value from storage |
89
- | `store.set(name, value)` | `name: string, value: any` | `void` | Save value to storage |
90
- | `store.remove(name)` | `name: string` | `boolean` | Remove single item |
91
- | `store.delete(name)` | `name: string` | `boolean` | Alias for remove |
92
- | `store.removeAll()` | none | `boolean` | Clear all storage |
93
- | `store.clearAll()` | none | `boolean` | Alias for removeAll |
94
- | `store.size()` | none | `number` | Get total size in characters |
95
- | `store.quota()` | none | `Promise<[number, number]>` | Get storage usage/quota in KB |
96
-
97
- ### Properties
98
-
99
- | Property | Type | Description |
100
- |----------|------|-------------|
101
- | `store.isPersistent` | `boolean` | `true` if using real localStorage, `false` if in-memory fallback |
102
-
103
- ### Supported Types
104
-
105
- ```javascript
106
- // All JSON-serializable types work
107
- store.set('string', 'hello');
108
- store.set('number', 42);
109
- store.set('boolean', true);
110
- store.set('array', [1, 2, 3]);
111
- store.set('object', { key: 'value' });
112
- store.set('null', null);
113
- store.set('undefined', null); // converted to null
114
- ```
115
-
116
- ### Not Supported
117
-
118
- ```javascript
119
- // Functions will log an error
120
- store.set('myFunc', () => {});
121
- // Output: "It's not secure to store functions."
122
- ```
123
-
124
- ---
125
-
126
- ## Platform Comparison
127
-
128
- | Feature | Store | Session | Cache | IDB |
129
- |---------|-------|---------|-------|-----|
130
- | **Storage** | localStorage | sessionStorage | Memory | IndexedDB |
131
- | **Lifetime** | Forever | Until tab closes | Until refresh | Forever |
132
- | **Capacity** | ~5-10 MB | ~5-10 MB | Unlimited | 50+ MB |
133
- | **Platform** | Browser/Edge | Browser/Edge | All | Browser |
134
- | **Persistence** | ✅ true | N/A | ❌ false | ✅ true |
135
-
136
- ---
137
-
138
- ## How It Works
139
-
140
- Store wraps the browser's `localStorage` API with:
141
-
142
- - Automatic JSON serialization/deserialization
143
- - Error handling for parse failures
144
- - Size calculation
145
- - Quota monitoring
146
-
147
- ---
148
-
149
- ## Storage Limits
150
-
151
- - **Chrome/Safari**: ~5-10 MB
152
- - **Firefox**: ~10 MB
153
- - **Edge**: ~5-10 MB
154
-
155
- Use `store.quota()` to monitor usage.
156
-
157
- ---
158
-
159
- ## Best Practices
160
-
161
- 1. Prefix keys: `store.set('app_username', '...')`
162
- 2. Check before set: `if (store.get('key')) { ... }`
163
- 3. Handle quota: Try/catch around large data
164
- 4. Clean up: `store.removeAll()` on logout
package/markdown/SYNC.md DELETED
@@ -1,170 +0,0 @@
1
- # Synchronization & Cloud (optional)
2
-
3
- `memorio.memory` is **local-first**. Data is created and served from the device;
4
- the cloud is only ever a **transport/persistence provider**, never the source of
5
- truth. Enabling sync does not replace local storage — it *mirrors* it.
6
-
7
- ```
8
- memorio
9
- │
10
- ┌────────┴────────┐
11
- │ Memory Engine │
12
- └────────┬────────┘
13
- ┌────────────┼────────────┐
14
- ▼ ▼ ▼
15
- local SQLite cloud
16
- memory durable sync
17
- ```
18
-
19
- ## 1. The rule: the data is born local
20
-
21
- ```ts
22
- memorio.memory.remember('user.language', 'Italian', { scope: 'local' })
23
- // ↓ local first
24
- // store / sessionStorage / IndexedDB / sql.js
25
- // ↓ sync / push (when online)
26
- // cloud provider
27
- ```
28
-
29
- The cloud therefore does not **replace** memory: it **replicates** it. This
30
- gives you: offline-first, lowest latency, data available immediately,
31
- synchronization when online, multi-device, multi-user, centralized persistence.
32
-
33
- We deliberately do **not** provide:
34
-
35
- ```ts
36
- // ❌ two mental models
37
- memory.cloud.save(...)
38
- ```
39
-
40
- Instead:
41
-
42
- ```ts
43
- memorio.memory.remember('user.language', 'Italian')
44
- // and a single configuration point:
45
- memorio.memory.configure({ sync: { provider: myCloudProvider, namespace: '…' } })
46
- ```
47
-
48
- ## 2. Scopes (isolation, not a security boundary)
49
-
50
- | Scope | Lifetime | Syncs by default |
51
- |---|---|---|
52
- | `'device'` | this browser/device only | no (sticky) |
53
- | `'user'` | follows the user across devices | yes (requires provider + namespace) |
54
- | `'shared'` | shared across users / tenant | yes (requires provider + namespace) |
55
-
56
- > As with `memorio.createContext`, **scoping is a naming convention, not a
57
- > security boundary.** Enforce real isolation server-side.
58
-
59
- ## 3. SQLite as the local durable store
60
-
61
- SQLite (`sql.js`) is **in-memory by default** (volatie per page load). It becomes
62
- the durable journal/value store when you opt in:
63
-
64
- - `sqlite.config({ persistence: true })` / `sqlite.db.create('app', { persistence: true })`
65
- snapshot the database to `store` (localStorage) and restore it on reopen.
66
- - Writes are snapshotted via sql.js `updateHook` (debounced).
67
- - `sqlite.db.persist(name)` forces an immediate save; `sqlite.db.close(name)`
68
- flushes + closes; `sqlite.db.download(name, file?)` triggers a browser
69
- `.sqlite` download (dev convenience).
70
-
71
- See `docs/markdown/SQLITE.md` for the full SQLite reference.
72
-
73
- ## 4. The local operation journal
74
-
75
- The **sync journal** is the durable op log that drives cloud reconciliation.
76
- It is persisted on `store` (localStorage) — **not** on an in-memory sql.js db,
77
- because pending operations must survive a refresh for offline-first to work.
78
-
79
- | Method | Returns | Notes |
80
- |---|---|---|
81
- | `memory.journal.append(entry, operation)` | `Promise<MemoryEntry>` | records `remember\|update\|forget\|expire\|confirm\|supersede` with `sync:'pending'` |
82
- | `memory.journal.pending()` | `Promise<MemoryEntry[]>` | rows where `sync != 'synced'`, for the current namespace |
83
- | `memory.journal.markSynced(ids)` | `Promise<number>` | advances rows to `synced` (namespace-scoped) |
84
- | `memory.journal.get(id)` | `Promise<MemoryEntry \| null>` | single entry, namespace-scoped |
85
- | `memory.journal.clear()` | `Promise<void>` | wipes the current namespace's journal |
86
- | `memory.journal.replay()` | `Promise<SyncAck>` | pushes `pending()` to the provider, marks synced, optional `pull` |
87
- | `memory.journal.status()` | `Promise<'store'>` | the substrate in use |
88
-
89
- We sync **operations of memory**, never a raw database dump:
90
-
91
- ```
92
- user A device A
93
- remember X ─────► local ─────► sync ─────► cloud
94
- forget Z ──────► local ─────► sync ─────► cloud
95
- ```
96
-
97
- ## 5. Conflict resolution
98
-
99
- The cloud must not simply say "last write wins." Memorio tags every entry with:
100
-
101
- - `confidence` (0–1, user/system trust in the value)
102
- - `lastConfirmedAt` / `updatedAt` (epoch ms)
103
- - `version` (monotonic per-key counter)
104
- - `source` / `scope`
105
-
106
- Remote conflicts are surfaced as `sync:'conflict'` rows via
107
- `journal.pending()`; the provider's `resolve(op)` hint decides locally. Example:
108
-
109
- ```
110
- Laptop: language=Italian, confidence=0.92
111
- Phone: language=English, confidence=0.61
112
- → higher-confidence entry wins locally; the provider decides for shared scope.
113
- ```
114
-
115
- ## 6. Configuring a backend
116
-
117
- Sync is **opt-in**. You supply an application-owned `provider` that knows how to
118
- talk to your backend (REST, WebSocket, Supabase, a custom agent server, …).
119
-
120
- ```ts
121
- memorio.memory.configure({
122
- namespace: 'user:123:device:abc', // tenant/user/device — partitions the journal
123
- provider: {
124
- push(ops) { return fetch('/api/sync', { method: 'POST', body: JSON.stringify(ops), headers: authHeaders }) }
125
- pull(since) { return fetch(`/api/sync?since=${since}`).then(r => r.json()) }
126
- resolve(op) { return op.confidence >= 0.8 ? 'local' : 'remote' }
127
- },
128
- auto: true // auto-replay on focus/online (default true)
129
- })
130
- ```
131
-
132
- ```ts
133
- interface SyncProvider {
134
- push(ops: MemoryEntry[]): Promise<{ synced: string[]; conflicts?: string[]; error?: string }>
135
- pull?(since?: number): Promise<MemoryEntry[]>
136
- resolve?(op: MemoryEntry): Promise<'local' | 'remote' | 'merge'>
137
- }
138
- ```
139
-
140
- `memorio.memory.ready` resolves once the local journal substrate is chosen.
141
-
142
- ## 7. Security (NIST / OWASP / NSA posture)
143
-
144
- - **Memorio never handles credentials.** No passwords, tokens, or API keys are
145
- read from or stored by memorio. Authentication/authorization live in your
146
- `provider`/backend (OWASP A01: Broken Access Control).
147
- - **Namespace isolation.** The journal is keyed by `namespace:id` at the storage
148
- layer; there is **no API** to enumerate or open another namespace's journal. A
149
- client holding a forged/fake namespace simply sees its own (empty) journal.
150
- - **No dynamic code.** Journal entries are strictly JSON-round-tripped,
151
- size-capped (10 MB/entry), and never `eval`'d. The sql.js loader never
152
- `import()`s a bare specifier that could be hijacked at build time.
153
- - **Trust boundary:** memorio owns the local durable copy + operation log; the
154
- provider/backend owns remote-side auth and conflict resolution. Memorio
155
- surfaces `conflict`/`error` rows; it does not fabricate a winner.
156
- - **Data-at-rest (NSA/CISA).** memorio's `store`/`idb`/`sqlite` snapshots are
157
- **not encrypted**. If you persist user data server-side or ship it through your
158
- backend, encrypt it server-side with keys you manage — memorio treats the local
159
- store as untrusted-from-the-browser and does not attest its own integrity.
160
-
161
- ## 8. Where data lives
162
-
163
- | Substrate | API | Volatile? | Persistent? |
164
- |---|---|---|---|
165
- | in-memory `Proxy` | `state` | yes (per tab) | no |
166
- | `localStorage` / Map | `store` | no | yes (browser) |
167
- | `sessionStorage` / Map | `session` | no | per-tab (browser) |
168
- | IndexedDB | `idb`, `memory` durable | no | yes |
169
- | sql.js (WASM heap) | `sqlite` | **yes** | only with `persistence: true` (snapshot → `store`) |
170
- | sync journal | `memory.journal` | no | yes (`store`) |
package/markdown/TYPED.md DELETED
@@ -1,158 +0,0 @@
1
- # Typed Stores - Memorio
2
-
3
- > ✅ **Universal**: Works in Browser, Node.js, Deno, and Edge Workers
4
-
5
- `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.
6
-
7
- 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.
8
-
9
- ---
10
-
11
- ## Quick Start
12
-
13
- ```typescript
14
- import 'memorio'
15
-
16
- interface AppState {
17
- user: { name: string; age: number; email: string }
18
- theme: 'light' | 'dark'
19
- items: string[]
20
- }
21
-
22
- const app = memorio.typed<AppState>()
23
-
24
- // Type-checked at compile time:
25
- app.user = { name: 'Sara', age: 30, email: 'sara@test.com' }
26
- app.theme = 'dark'
27
-
28
- // TypeScript errors:
29
- // app.user = { name: 42 } // age missing, name wrong type
30
- // app.theme = 'purple' // not a valid literal
31
- ```
32
-
33
- ---
34
-
35
- ## Why use typed stores?
36
-
37
- | Without typed | With `memorio.typed<T>()` |
38
- |---|---|
39
- | `state.user = { name: 42 }` — runs silently, bug at runtime | `app.user = { name: 42 }` — TypeScript error at compile time |
40
- | No autocomplete on `state.user.email` | Full IntelliSense: properties, types, method suggestions |
41
- | Rename `user` to `profile` — no compiler warning anywhere | Every `app.user` access flagged as an error |
42
- | AI-generated code lacks guardrails | AI gets autocomplete and type feedback inline |
43
-
44
- ---
45
-
46
- ## Combine with Schema Validation
47
-
48
- Typed stores catch type errors at compile time; schema validation catches invalid values at runtime. Together they form a **defense-in-depth** strategy:
49
-
50
- ```typescript
51
- import 'memorio'
52
-
53
- interface ProfileState {
54
- profile: { bio: string; avatar?: string }
55
- }
56
-
57
- const app = memorio.typed<ProfileState>()
58
-
59
- memorio.registerSchema('profile', {
60
- type: 'object',
61
- required: ['bio'],
62
- properties: {
63
- bio: { type: 'string', min: 1 },
64
- avatar: { type: 'string' }
65
- }
66
- })
67
-
68
- app.profile = { bio: 'Developer', avatar: 'pic.png' } // ✅ type + schema pass
69
- app.profile = { avatar: 'pic.png' } // ❌ TypeScript: bio missing
70
- // ❌ Runtime: bio required
71
- ```
72
-
73
- See [Schema Validation](SCHEMA.md) for runtime validation details.
74
-
75
- ---
76
-
77
- ## Named import variant
78
-
79
- `typed` is also available as a named export if you prefer explicit dependencies:
80
-
81
- ```typescript
82
- import { typed } from 'memorio'
83
-
84
- const app = typed<AppState>()
85
- ```
86
-
87
- The `memorio` namespace object is the same — `import 'memorio'` is the recommended entry, named exports are an alternative.
88
-
89
- ---
90
-
91
- ## Full API
92
-
93
- | Method | Parameters | Returns | Description |
94
- |--------|-----------|---------|-------------|
95
- | `memorio.typed<T>()` | Generic type `T` | `T` | Returns the global `state` proxy cast to `T` |
96
-
97
- The returned object shares the same identity as `globalThis.state`:
98
-
99
- ```typescript
100
- const app = memorio.typed<AppState>()
101
- console.debug(app === state) // true — same Proxy instance
102
- ```
103
-
104
- ---
105
-
106
- ## React + typed stores
107
-
108
- Pair with the `useObserver` hook for type-safe, reactive React components:
109
-
110
- ```tsx
111
- import 'memorio'
112
- import { useReducer } from 'react'
113
-
114
- interface AppState {
115
- user: { name: string; age: number }
116
- theme: 'light' | 'dark'
117
- }
118
-
119
- const app = memorio.typed<AppState>()
120
-
121
- function UserProfile() {
122
- const [, forceUpdate] = useReducer(x => x + 1, 0)
123
-
124
- useObserver(forceUpdate, [state.user.name])
125
-
126
- return (
127
- <div>
128
- <h1>{app.user.name}</h1>
129
- <span>Theme: {app.theme}</span>
130
- </div>
131
- )
132
- }
133
- ```
134
-
135
- ---
136
-
137
- ## Best Practices
138
-
139
- 1. **Define your AppState at the root** of your app and import it everywhere:
140
-
141
- ```typescript
142
- // types/app-state.ts
143
- export interface AppState {
144
- user: { name: string; email: string }
145
- theme: 'light' | 'dark'
146
- }
147
- ```
148
-
149
- ```typescript
150
- // anywhere in your app
151
- import 'memorio'
152
- import type { AppState } from '../types/app-state'
153
- const app = memorio.typed<AppState>()
154
- ```
155
-
156
- 2. **Layer schema validation on top** for runtime safety, especially for data coming from APIs or user input.
157
-
158
- 3. **Use alongside `memorio.help()`** to list available globals during development.