memorio 4.1.6 → 4.2.1
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 +16 -57
- package/index.cjs +436 -385
- package/index.js +436 -385
- package/{docs/markdown → markdown}/PLATFORM.md +10 -9
- package/{docs/markdown → markdown}/SECURITY.md +15 -10
- package/package.json +1 -1
- package/types/memorio.d.ts +1 -0
- package/docs/README.md +0 -307
- package/docs/_config.yml +0 -1
- /package/{docs/SUMMARY.md → SUMMARY.md} +0 -0
- /package/{docs/markdown → markdown}/CACHE.md +0 -0
- /package/{docs/markdown → markdown}/CHANGELOG.md +0 -0
- /package/{docs/markdown → markdown}/DEVTOOLS.md +0 -0
- /package/{docs/markdown → markdown}/IDB.md +0 -0
- /package/{docs/markdown → markdown}/LOGGER.md +0 -0
- /package/{docs/markdown → markdown}/OBSERVER.md +0 -0
- /package/{docs/markdown → markdown}/SESSION.md +0 -0
- /package/{docs/markdown → markdown}/STATE.md +0 -0
- /package/{docs/markdown → markdown}/STORE.md +0 -0
- /package/{docs/markdown → markdown}/USEOBSERVER.md +0 -0
|
@@ -125,9 +125,8 @@ session.isPersistent; // false - data lost on restart
|
|
|
125
125
|
Each instance/session gets unique storage keys to prevent conflicts:
|
|
126
126
|
|
|
127
127
|
```javascript
|
|
128
|
-
//
|
|
129
|
-
//
|
|
130
|
-
// session: "memorio_session_[sessionId]_key"
|
|
128
|
+
// Without context: "memorio_store_[sessionId]_key"
|
|
129
|
+
// With context: "[contextName]-key"
|
|
131
130
|
```
|
|
132
131
|
|
|
133
132
|
This ensures:
|
|
@@ -146,7 +145,11 @@ For server-side applications handling multiple tenants (e.g., different users/re
|
|
|
146
145
|
|
|
147
146
|
```javascript
|
|
148
147
|
// Create isolated context for a user/session
|
|
149
|
-
const ctx = memorio.
|
|
148
|
+
const ctx = memorio.isolate('user-123');
|
|
149
|
+
|
|
150
|
+
// Keys in store/session are prefixed with context name
|
|
151
|
+
// store: "user-123-key"
|
|
152
|
+
// session: "user-123-key"
|
|
150
153
|
|
|
151
154
|
// Use context's isolated storage
|
|
152
155
|
ctx.state.user = { name: 'Isolated User' };
|
|
@@ -167,11 +170,10 @@ console.debug(contexts); // ['user-123', 'user-456', ...]
|
|
|
167
170
|
|
|
168
171
|
// Delete a context (cleanup)
|
|
169
172
|
memorio.deleteContext('user-123');
|
|
170
|
-
|
|
171
|
-
// Shorthand for createContext
|
|
172
|
-
const ctx2 = memorio.isolate('tenant-A');
|
|
173
173
|
```
|
|
174
174
|
|
|
175
|
+
> **Note**: `memorio.isolate('name')` is a shorthand alias for creating isolated contexts.
|
|
176
|
+
|
|
175
177
|
### Context Use Cases
|
|
176
178
|
|
|
177
179
|
#### 1. Per-Request Isolation (Express/Fastify)
|
|
@@ -246,10 +248,9 @@ Same as browser - localStorage and sessionStorage are available.
|
|
|
246
248
|
|
|
247
249
|
| Function | Returns | Description |
|
|
248
250
|
|----------|---------|-------------|
|
|
249
|
-
| `memorio.
|
|
251
|
+
| `memorio.isolate(name?)` | `Context` | Create isolated context |
|
|
250
252
|
| `memorio.listContexts()` | `string[]` | List all context IDs |
|
|
251
253
|
| `memorio.deleteContext(id)` | `boolean` | Delete a context |
|
|
252
|
-
| `memorio.isolate(name?)` | `Context` | Alias for createContext |
|
|
253
254
|
|
|
254
255
|
### Properties
|
|
255
256
|
|
|
@@ -108,18 +108,23 @@ Each session gets a unique namespace to prevent data leakage:
|
|
|
108
108
|
|
|
109
109
|
### Isolation Mechanism
|
|
110
110
|
|
|
111
|
-
| Component |
|
|
112
|
-
|
|
113
|
-
| Session ID | `crypto.randomUUID()` |
|
|
114
|
-
| Store Keys | `memorio_store_[uuid]
|
|
115
|
-
| Session Keys | `memorio_session_[uuid]
|
|
116
|
-
| State | In-memory (per-instance) |
|
|
111
|
+
| Component | Without Context | With Context |
|
|
112
|
+
|-----------|-----------------|--------------|
|
|
113
|
+
| Session ID | `crypto.randomUUID()` | Context name |
|
|
114
|
+
| Store Keys | `memorio_store_[uuid]-keyname` | `[contextName]-keyname` |
|
|
115
|
+
| Session Keys | `memorio_session_[uuid]-keyname` | `[contextName]-keyname` |
|
|
116
|
+
| State | In-memory (per-instance) | In-memory (per-instance) |
|
|
117
117
|
|
|
118
118
|
### Key Prefix Format
|
|
119
119
|
|
|
120
120
|
```
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
// Without context:
|
|
122
|
+
memorio_store-[session-uuid]-username
|
|
123
|
+
memorio_session-[session-uuid]-auth-token
|
|
124
|
+
|
|
125
|
+
// With context (createContext('user-123')):
|
|
126
|
+
user-123-username
|
|
127
|
+
user-123-auth-token
|
|
123
128
|
```
|
|
124
129
|
|
|
125
130
|
### Cross-Session Protection
|
|
@@ -138,8 +143,8 @@ For server-side applications, contexts provide complete data isolation:
|
|
|
138
143
|
|
|
139
144
|
```typescript
|
|
140
145
|
// Create isolated context per tenant
|
|
141
|
-
const tenantA = memorio.
|
|
142
|
-
const tenantB = memorio.
|
|
146
|
+
const tenantA = memorio.isolate('tenant-A')
|
|
147
|
+
const tenantB = memorio.isolate('tenant-B')
|
|
143
148
|
|
|
144
149
|
// Each context has completely separate storage
|
|
145
150
|
tenantA.state.secret = 'Tenant A data' // Isolated
|
package/package.json
CHANGED
package/types/memorio.d.ts
CHANGED
package/docs/README.md
DELETED
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
# [memorio](https://npmjs.com/package/memorio)
|
|
2
|
-
|
|
3
|
-

|
|
4
|
-
|
|
5
|
-

|
|
6
|
-

|
|
7
|
-

|
|
8
|
-
|
|
9
|
-

|
|
10
|
-

|
|
11
|
-

|
|
12
|
-

|
|
13
|
-

|
|
14
|
-

|
|
15
|
-
|
|
16
|
-
**State management that actually makes your life easier.**
|
|
17
|
-
Zero friction. Zero bloat. Single import. Works everywhere JavaScript runs.
|
|
18
|
-
|
|
19
|
-
[Get Started](#-quick-start) · [API Reference](#-api-reference) · [License: MIT](https://opensource.org/licenses/MIT)
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## Why memorio?
|
|
24
|
-
|
|
25
|
-
| | memorio | Redux | Zustand |
|
|
26
|
-
|---|---|---|---|
|
|
27
|
-
| **Setup** | 1 import | Boilerplate hell | Moderate |
|
|
28
|
-
| **Dependencies** | **Zero** | Many | Few |
|
|
29
|
-
| **TypeScript** | ✅ Native | ✅ | ✅ |
|
|
30
|
-
| **Binary storage** | ✅ Built-in IDB | ❌ Add-on | ❌ |
|
|
31
|
-
| **Observer** | ✅ Built-in | ❌ Add-on | ❌ |
|
|
32
|
-
| **DevTools** | ✅ Built-in + dphelper-manager extension | ❌ Extension | ❌ |
|
|
33
|
-
| **Running on the edge** | ✅ Workers, Deno | ⚠️ Limited | ⚠️ Limited |
|
|
34
|
-
|
|
35
|
-
If you need a `store` on the server. A `cache` in the edge worker.
|
|
36
|
-
Session isolation in Next.js. IndexedDB in a Service Worker.
|
|
37
|
-
All from one import, zero configuration.
|
|
38
|
-
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
## Features
|
|
42
|
-
|
|
43
|
-
| | |
|
|
44
|
-
|---|---|
|
|
45
|
-
| **`state`** | Reactive, volatile state — listen with `useObserver` |
|
|
46
|
-
| **`store`** | localStorage persistence — survives refresh |
|
|
47
|
-
| **`session`** | sessionStorage — dies with the tab |
|
|
48
|
-
| **`cache`** | In-memory cache — fastest read possible |
|
|
49
|
-
| **`idb`** | IndexedDB with typed tables — structured, persistent, async |
|
|
50
|
-
| **`observer`** | Object watcher — legacy, still works |
|
|
51
|
-
| **`useObserver`** | React hook with auto-discovery — drops in |
|
|
52
|
-
| **`devtools`** | `memorio.devtools.inspect()` — see everything in console |
|
|
53
|
-
| **`logger`** | Auto-log every state change with timestamps |
|
|
54
|
-
| **Session Isolation** | Every browser tab, every request: isolated namespace |
|
|
55
|
-
| **Platform Detection** | `isBrowser`, `isNode`, `isDeno`, `isEdge` |
|
|
56
|
-
|
|
57
|
-
No Zustand. No Redux. No provider boilerplate.
|
|
58
|
-
Just import it and start storing.
|
|
59
|
-
|
|
60
|
-
---
|
|
61
|
-
|
|
62
|
-
## Quick Start
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
npm i memorio
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
```typescript
|
|
69
|
-
// memorio/index.ts — import once at your app entry point
|
|
70
|
-
import 'memorio'
|
|
71
|
-
|
|
72
|
-
// Memory
|
|
73
|
-
state.user = { name: 'Sara', role: 'admin' }
|
|
74
|
-
state.counter++
|
|
75
|
-
state.settings = { theme: 'dark', lang: 'it' }
|
|
76
|
-
|
|
77
|
-
// Call it "a store" but make it observe automatically
|
|
78
|
-
useObserver(
|
|
79
|
-
() => { console.debug('user changed:', state.user) },
|
|
80
|
-
[state.user]
|
|
81
|
-
)
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
That is it.
|
|
85
|
-
No context providers. No `<Store>` wrappers. No action creators.
|
|
86
|
-
Import → assign → done.
|
|
87
|
-
|
|
88
|
-
---
|
|
89
|
-
|
|
90
|
-
## API Reference
|
|
91
|
-
|
|
92
|
-
### `state` — Volatile reactive state
|
|
93
|
-
|
|
94
|
-
Global, Proxy-based, reactive. Access anywhere.
|
|
95
|
-
|
|
96
|
-
```javascript
|
|
97
|
-
// Set
|
|
98
|
-
state.user = { name: 'Sara', role: 'admin' }
|
|
99
|
-
state.items = [1, 2, 3]
|
|
100
|
-
|
|
101
|
-
// Get
|
|
102
|
-
const name = state.user.name // 'Sara'
|
|
103
|
-
|
|
104
|
-
// List all keys
|
|
105
|
-
console.debug(state.list) // ['user', 'items']
|
|
106
|
-
|
|
107
|
-
// Remove one key
|
|
108
|
-
state.remove('items')
|
|
109
|
-
|
|
110
|
-
// Clear all — lock/unlock available for frozen objects
|
|
111
|
-
state.removeAll()
|
|
112
|
-
state.lock() // freeze everything
|
|
113
|
-
state.unlock() // unfreeze
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
### `store` — localStorage, survives refresh
|
|
117
|
-
|
|
118
|
-
```javascript
|
|
119
|
-
store.set('preferences', { theme: 'dark' })
|
|
120
|
-
const prefs = store.get('preferences') // { theme: 'dark' } or null
|
|
121
|
-
store.remove('preferences')
|
|
122
|
-
store.removeAll()
|
|
123
|
-
console.debug(store.size(), 'chars stored')
|
|
124
|
-
console.debug(store.isPersistent) // true → real localStorage
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
### `session` — sessionStorage, dies with tab
|
|
128
|
-
|
|
129
|
-
```javascript
|
|
130
|
-
session.set('token', 'user-abc-123')
|
|
131
|
-
const token = session.get('token') // 'user-abc-123' or null
|
|
132
|
-
session.removeAll()
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### `cache` — In-memory, disappears on refresh
|
|
136
|
-
|
|
137
|
-
```javascript
|
|
138
|
-
cache.set('temp', computeExpensiveResult())
|
|
139
|
-
const result = cache.get('temp') // undefined or the value
|
|
140
|
-
cache.clear() // empty it all
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
### `idb` — IndexedDB, structured & typed
|
|
144
|
-
|
|
145
|
-
```javascript
|
|
146
|
-
await idb.db.create('my-db')
|
|
147
|
-
await idb.table.create('my-db', 'users')
|
|
148
|
-
await idb.data.set('my-db', 'users', { id: 1, name: 'Sara' })
|
|
149
|
-
const user = await idb.data.get('my-db', 'users', 1)
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
### `observer` — Object watcher (DEPRECATED)
|
|
153
|
-
|
|
154
|
-
```javascript
|
|
155
|
-
globalThis.observer('state.user', (newVal, oldVal) => {
|
|
156
|
-
console.debug('user changed:', newVal, oldVal)
|
|
157
|
-
})
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
### `useObserver` — React observer hook
|
|
161
|
-
|
|
162
|
-
Available globally after `import 'memorio'`.
|
|
163
|
-
|
|
164
|
-
```jsx
|
|
165
|
-
import 'memorio'
|
|
166
|
-
|
|
167
|
-
function Counter() {
|
|
168
|
-
const [, forceUpdate] = useReducer(x => x + 1, 0)
|
|
169
|
-
|
|
170
|
-
useObserver(forceUpdate, [state.counter])
|
|
171
|
-
// State path auto-discovered during render — no manual deps needed
|
|
172
|
-
|
|
173
|
-
return <div>Count: {state.counter}</div>
|
|
174
|
-
}
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
### `devtools` — inspect everything in one call
|
|
178
|
-
|
|
179
|
-
```javascript
|
|
180
|
-
memorio.devtools.inspect() // pretty-prints state, store, session, cache
|
|
181
|
-
memorio.devtools.stats() // { stateKeys, storeKeys, sessionKeys, ... }
|
|
182
|
-
memorio.devtools.clear('state')
|
|
183
|
-
memorio.devtools.exportData() // JSON snapshot
|
|
184
|
-
$state // console shortcut — same as globalThis.state
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
> **Browser Extension Integration:** When used with dphelper-manager browser extension, memorio's global state namespace is automatically detected and visualized through a dedicated DevTools panel, providing time-travel debugging and structural guardrails.
|
|
188
|
-
|
|
189
|
-
### `logger` — track every change
|
|
190
|
-
|
|
191
|
-
```javascript
|
|
192
|
-
memorio.logger.configure({ enabled: true, logToConsole: true })
|
|
193
|
-
memorio.logger.getHistory() // [{ timestamp, module, action, path, value }, ...]
|
|
194
|
-
memorio.logger.getStats() // { total, state, set, get, ... }
|
|
195
|
-
memorio.logger.exportLogs() // JSON string of all history
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
### Platform detection
|
|
199
|
-
|
|
200
|
-
Access via `memorio.*`:
|
|
201
|
-
|
|
202
|
-
```javascript
|
|
203
|
-
memorio.isBrowser() // true in Chrome, Firefox, Safari
|
|
204
|
-
memorio.isNode() // true in Node.js
|
|
205
|
-
memorio.isDeno() // true in Deno
|
|
206
|
-
memorio.isEdge() // true in Cloudflare Workers, Vercel Edge
|
|
207
|
-
|
|
208
|
-
const caps = memorio.getCapabilities()
|
|
209
|
-
// { platform: 'browser', hasLocalStorage: true, hasIndexedDB: true, ... }
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
### Context (multi-tenant)
|
|
213
|
-
|
|
214
|
-
```javascript
|
|
215
|
-
memorio.createContext('tenant-name')
|
|
216
|
-
memorio.listContexts()
|
|
217
|
-
memorio.deleteContext('context-id')
|
|
218
|
-
memorio.isolate('tenant-name')
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
---
|
|
222
|
-
|
|
223
|
-
## Cross-Platform
|
|
224
|
-
|
|
225
|
-
Memorio runs in every JavaScript environment, with automatic fallbacks.
|
|
226
|
-
|
|
227
|
-
| | Browser | Node.js | Deno | Edge / Workers |
|
|
228
|
-
|---|---|---|---|---|
|
|
229
|
-
| `state` | ✅ | ✅ | ✅ | ✅ |
|
|
230
|
-
| `observer` / `useObserver` | ✅ | ✅ | ✅ | ✅ |
|
|
231
|
-
| `cache` | ✅ | ✅ | ✅ | ✅ |
|
|
232
|
-
| `store` | ✅ localStorage | ⚠️ memory | ⚠️ memory | ✅ localStorage |
|
|
233
|
-
| `session` | ✅ sessionStorage | ⚠️ memory | ⚠️ memory | ✅ sessionStorage |
|
|
234
|
-
| `idb` | ✅ IndexedDB | ❌ | ❌ | ⚠️ |
|
|
235
|
-
| `devtools` | ✅ | ❌ | ❌ | ⚠️ |
|
|
236
|
-
|
|
237
|
-
> **Why memory fallbacks on the server?** There is no browser. `store` and `session` gracefully fall back to `Map`. You still get the same API. Same `state`, same `cache`, same `useObserver`. No extra config required.
|
|
238
|
-
|
|
239
|
-
### Platform detection
|
|
240
|
-
|
|
241
|
-
Access via `memorio.*` after `import 'memorio'`:
|
|
242
|
-
|
|
243
|
-
```javascript
|
|
244
|
-
memorio.isBrowser() // true in Chrome, Firefox, Safari
|
|
245
|
-
memorio.isNode() // true in Node.js
|
|
246
|
-
memorio.isDeno() // true in Deno
|
|
247
|
-
memorio.isEdge() // true in Cloudflare Workers, Vercel Edge
|
|
248
|
-
|
|
249
|
-
const c = memorio.getCapabilities()
|
|
250
|
-
// { platform: 'browser', hasLocalStorage: true, hasIndexedDB: true, ... }
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
---
|
|
254
|
-
|
|
255
|
-
## Security
|
|
256
|
-
|
|
257
|
-
- Zero production dependencies — no supply chain surprises
|
|
258
|
-
- NIST & NSA aligned — enterprise-grade security standards
|
|
259
|
-
- No `eval`, no obfuscation, no hardcoded secrets
|
|
260
|
-
- All inputs validated, keys sanitized, errors caught
|
|
261
|
-
- Secure random session IDs via `crypto.randomUUID`
|
|
262
|
-
- MIT license — full audit trail on [`SECURITY.md`](.github/SECURITY.md)
|
|
263
|
-
|
|
264
|
-
---
|
|
265
|
-
|
|
266
|
-
## Installation options
|
|
267
|
-
|
|
268
|
-
```bash
|
|
269
|
-
# npm
|
|
270
|
-
npm i memorio
|
|
271
|
-
|
|
272
|
-
# pnpm
|
|
273
|
-
pnpm add memorio
|
|
274
|
-
|
|
275
|
-
# yarn
|
|
276
|
-
yarn add memorio
|
|
277
|
-
|
|
278
|
-
# React peer dep (optional, React ≥ 16.8)
|
|
279
|
-
npm i react react-dom
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
---
|
|
283
|
-
|
|
284
|
-
## Testing
|
|
285
|
-
|
|
286
|
-
```
|
|
287
|
-
95 tests · 8 suites · all passing
|
|
288
|
-
|
|
289
|
-
basic | state | store | session | cache | idb | observer | useObserver
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
| Suite | Tests | Status |
|
|
293
|
-
|-------|-------|--------|
|
|
294
|
-
| Basic | 7 | ✅ |
|
|
295
|
-
| State | 24 | ✅ |
|
|
296
|
-
| Store | 17 | ✅ |
|
|
297
|
-
| Session | 12 | ✅ |
|
|
298
|
-
| IDB | 7 | ✅ |
|
|
299
|
-
| Cache | 5 | ✅ |
|
|
300
|
-
| Observer | 12 | ✅ |
|
|
301
|
-
| useObserver | 12 | ✅ |
|
|
302
|
-
|
|
303
|
-
---
|
|
304
|
-
|
|
305
|
-
## License
|
|
306
|
-
|
|
307
|
-
MIT © [Dario Passariello](https://dario.passariello.ca)
|
package/docs/_config.yml
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
theme: jekyll-theme-modernist
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|