memorio 4.6.8 → 4.7.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/COPYRIGHT.md +6 -0
- package/FUNDING.yml +12 -0
- package/SECURITY.md +48 -0
- package/SUMMARY.md +28 -0
- package/index.cjs +54 -0
- package/index.d.ts +18 -0
- package/index.js +54 -0
- package/llms.txt +405 -0
- package/markdown/CACHE.md +90 -0
- package/markdown/CHANGELOG.md +161 -0
- package/markdown/DEVTOOLS.md +122 -0
- package/markdown/DISPATCH.md +168 -0
- package/markdown/IDB.md +169 -0
- package/markdown/IMPORT.md +139 -0
- package/markdown/LOGGER.md +147 -0
- package/markdown/OBSERVER.md +200 -0
- package/markdown/PLATFORM.md +265 -0
- package/markdown/SECURITY.md +323 -0
- package/markdown/SESSION.md +154 -0
- package/markdown/STATE.md +153 -0
- package/markdown/STORE.md +164 -0
- package/markdown/USEOBSERVER.md +259 -0
- package/package.json +13 -3
package/llms.txt
ADDED
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
# Memorio - LLM Documentation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
**Memorio** is a cross-platform state management library that provides reactive state, persistence, and observation capabilities with zero dependencies. It works in Node.js, Deno, browsers, and edge environments.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
npm i memorio
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Core Concepts
|
|
12
|
+
|
|
13
|
+
Memorio provides 6 storage modules plus utilities:
|
|
14
|
+
|
|
15
|
+
| Module | Purpose | Persistence |
|
|
16
|
+
|--------|---------|-------------|
|
|
17
|
+
| `state` | Reactive, volatile state | In-memory (resets on refresh) |
|
|
18
|
+
| `store` | localStorage persistence | Survives browser refresh |
|
|
19
|
+
| `session` | sessionStorage | Dies with browser tab |
|
|
20
|
+
| `cache` | In-memory cache | Fastest read, no persistence |
|
|
21
|
+
| `idb` | IndexedDB | Structured, async, persistent (browser-only) |
|
|
22
|
+
| `observer` | Object watcher | Legacy |
|
|
23
|
+
| `useObserver` | React hook | Auto-discovery of state paths |
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
import 'memorio'
|
|
29
|
+
|
|
30
|
+
// Set reactive state
|
|
31
|
+
state.user = { name: 'Sara', role: 'admin' }
|
|
32
|
+
state.counter = 0
|
|
33
|
+
|
|
34
|
+
// Observe changes (React hook)
|
|
35
|
+
useObserver(
|
|
36
|
+
() => { console.debug('counter:', state.counter) },
|
|
37
|
+
[state.counter]
|
|
38
|
+
)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## API Reference
|
|
42
|
+
|
|
43
|
+
### `state` — Reactive State
|
|
44
|
+
|
|
45
|
+
Global, Proxy-based, reactive state management.
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
// Set values
|
|
49
|
+
state.user = { name: 'Sara', role: 'admin' }
|
|
50
|
+
state.items = [1, 2, 3]
|
|
51
|
+
state.counter = 0
|
|
52
|
+
|
|
53
|
+
// Get values
|
|
54
|
+
const name = state.user.name // 'Sara'
|
|
55
|
+
|
|
56
|
+
// List all keys
|
|
57
|
+
console.debug(state.list) // ['user', 'items', 'counter']
|
|
58
|
+
|
|
59
|
+
// Remove one key
|
|
60
|
+
state.remove('items')
|
|
61
|
+
|
|
62
|
+
// Clear all
|
|
63
|
+
state.removeAll()
|
|
64
|
+
|
|
65
|
+
// Lock/unlock for frozen objects
|
|
66
|
+
state.lock() // freeze everything
|
|
67
|
+
state.unlock() // unfreeze
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Features:**
|
|
71
|
+
- Automatic path tracking via `__path` property
|
|
72
|
+
- Nested proxy support
|
|
73
|
+
- Lock/unlock per-key or globally
|
|
74
|
+
- Auto-dispatches events on changes
|
|
75
|
+
|
|
76
|
+
### `store` — localStorage Persistence
|
|
77
|
+
|
|
78
|
+
Persistent storage that survives browser refresh.
|
|
79
|
+
|
|
80
|
+
```javascript
|
|
81
|
+
// Set
|
|
82
|
+
store.set('preferences', { theme: 'dark' })
|
|
83
|
+
|
|
84
|
+
// Get
|
|
85
|
+
const prefs = store.get('preferences') // { theme: 'dark' } or null
|
|
86
|
+
|
|
87
|
+
// List all keys
|
|
88
|
+
store.list() // { preferences: { theme: 'dark' } }
|
|
89
|
+
|
|
90
|
+
// Remove
|
|
91
|
+
store.remove('preferences')
|
|
92
|
+
|
|
93
|
+
// Delete (alias for remove)
|
|
94
|
+
store.delete('preferences')
|
|
95
|
+
|
|
96
|
+
// Clear all memorio items
|
|
97
|
+
store.removeAll()
|
|
98
|
+
|
|
99
|
+
// Clear all (alias for removeAll)
|
|
100
|
+
store.clearAll()
|
|
101
|
+
|
|
102
|
+
// Check size
|
|
103
|
+
console.debug(store.size(), 'chars stored')
|
|
104
|
+
|
|
105
|
+
// Check if persistent (real localStorage vs memory fallback)
|
|
106
|
+
console.debug(store.isPersistent) // true → real localStorage
|
|
107
|
+
|
|
108
|
+
// Estimate quota usage (returns [0, 0] for localStorage)
|
|
109
|
+
await store.quota() // [usage, quota] in KB
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### `session` — sessionStorage
|
|
113
|
+
|
|
114
|
+
Storage that dies when browser tab closes.
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
// Set
|
|
118
|
+
session.set('token', 'user-abc-123')
|
|
119
|
+
|
|
120
|
+
// Get
|
|
121
|
+
const token = session.get('token') // 'user-abc-123' or null
|
|
122
|
+
|
|
123
|
+
// List all keys
|
|
124
|
+
session.list() // { token: 'user-abc-123' }
|
|
125
|
+
|
|
126
|
+
// Remove
|
|
127
|
+
session.remove('token')
|
|
128
|
+
|
|
129
|
+
// Delete (alias for remove)
|
|
130
|
+
session.delete('token')
|
|
131
|
+
|
|
132
|
+
// Clear all
|
|
133
|
+
session.removeAll()
|
|
134
|
+
|
|
135
|
+
// Clear all (alias for removeAll)
|
|
136
|
+
session.clearAll()
|
|
137
|
+
|
|
138
|
+
// Check size
|
|
139
|
+
console.debug(session.size(), 'chars stored')
|
|
140
|
+
|
|
141
|
+
// Check if persistent
|
|
142
|
+
console.debug(session.isPersistent)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### `cache` — In-Memory Cache
|
|
146
|
+
|
|
147
|
+
Fastest possible read, data lost on refresh.
|
|
148
|
+
|
|
149
|
+
```javascript
|
|
150
|
+
// Set
|
|
151
|
+
cache.set('temp', computeExpensiveResult())
|
|
152
|
+
|
|
153
|
+
// Get
|
|
154
|
+
const result = cache.get('temp') // undefined or the value
|
|
155
|
+
|
|
156
|
+
// List all keys
|
|
157
|
+
cache.list() // { temp: <value> }
|
|
158
|
+
|
|
159
|
+
// Remove
|
|
160
|
+
cache.remove('temp')
|
|
161
|
+
|
|
162
|
+
// Clear all
|
|
163
|
+
cache.clear()
|
|
164
|
+
|
|
165
|
+
// Remove all (alias for clear)
|
|
166
|
+
cache.removeAll()
|
|
167
|
+
|
|
168
|
+
// Direct access (also works)
|
|
169
|
+
cache['myKey'] = value
|
|
170
|
+
const value = cache['myKey']
|
|
171
|
+
delete cache['myKey']
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### `idb` — IndexedDB
|
|
175
|
+
|
|
176
|
+
Structured, persistent, async database (browser-only).
|
|
177
|
+
|
|
178
|
+
```javascript
|
|
179
|
+
// Create database
|
|
180
|
+
await idb.db.create('my-db', 1) // version defaults to 1
|
|
181
|
+
|
|
182
|
+
// Create table (object store)
|
|
183
|
+
await idb.table.create('my-db', 'users')
|
|
184
|
+
|
|
185
|
+
// Set data
|
|
186
|
+
await idb.data.set('my-db', 'users', { id: 1, name: 'Sara' })
|
|
187
|
+
|
|
188
|
+
// Get data by key
|
|
189
|
+
const user = await idb.data.get('my-db', 'users', 1)
|
|
190
|
+
|
|
191
|
+
// Delete data
|
|
192
|
+
await idb.data.delete('my-db', 'users', 1)
|
|
193
|
+
|
|
194
|
+
// List databases
|
|
195
|
+
const dbs = await idb.db.list()
|
|
196
|
+
|
|
197
|
+
// Check if database exists
|
|
198
|
+
const exists = await idb.db.exist('my-db')
|
|
199
|
+
|
|
200
|
+
// Delete database
|
|
201
|
+
await idb.db.delete('my-db')
|
|
202
|
+
|
|
203
|
+
// Get database size
|
|
204
|
+
const size = await idb.db.size('my-db')
|
|
205
|
+
|
|
206
|
+
// Get table size
|
|
207
|
+
const tableSize = await idb.table.size('my-db', 'users')
|
|
208
|
+
|
|
209
|
+
// Check support
|
|
210
|
+
idb.db.support() // true if IndexedDB available
|
|
211
|
+
|
|
212
|
+
// Check quota
|
|
213
|
+
const [usage, quota] = await idb.db.quota()
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**Note:** In Node.js/Deno, `idb` is disabled with a warning. Use `store` or `session` instead.
|
|
217
|
+
|
|
218
|
+
### `observer` — Object Watcher
|
|
219
|
+
|
|
220
|
+
Legacy observer API. Use `useObserver` instead.
|
|
221
|
+
|
|
222
|
+
```javascript
|
|
223
|
+
// Listen to state changes
|
|
224
|
+
observer('state.user', (newVal, oldVal) => {
|
|
225
|
+
console.debug('user changed:', newVal, oldVal)
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
// Toggle listening (no callback)
|
|
229
|
+
observer('state.counter')
|
|
230
|
+
|
|
231
|
+
// Remove observer
|
|
232
|
+
observer.remove('state.user')
|
|
233
|
+
|
|
234
|
+
// List all observers
|
|
235
|
+
console.debug(observer.list)
|
|
236
|
+
|
|
237
|
+
// Remove all observers
|
|
238
|
+
observer.removeAll()
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### `useObserver` — React Hook
|
|
242
|
+
|
|
243
|
+
Primary way to observe state changes in React components.
|
|
244
|
+
|
|
245
|
+
```jsx
|
|
246
|
+
import 'memorio'
|
|
247
|
+
import { useReducer } from 'react'
|
|
248
|
+
|
|
249
|
+
function Counter() {
|
|
250
|
+
const [, forceUpdate] = useReducer(x => x + 1, 0)
|
|
251
|
+
|
|
252
|
+
// Auto-discovery mode (no deps)
|
|
253
|
+
useObserver(() => {
|
|
254
|
+
console.debug('counter:', state.counter)
|
|
255
|
+
}, state.counter)
|
|
256
|
+
|
|
257
|
+
// Explicit deps mode
|
|
258
|
+
useObserver(
|
|
259
|
+
() => { console.debug('user:', state.user) },
|
|
260
|
+
[state.user]
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
return <div>Count: {state.counter}</div>
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
**Features:**
|
|
268
|
+
- Auto-discovery of state paths during render
|
|
269
|
+
- Returns cleanup function to stop monitoring
|
|
270
|
+
- Supports both Proxy objects and string paths
|
|
271
|
+
|
|
272
|
+
### `devtools` — Inspection Tools
|
|
273
|
+
|
|
274
|
+
Inspect all memorio data in console.
|
|
275
|
+
|
|
276
|
+
```javascript
|
|
277
|
+
// Pretty-print state, store, session, cache
|
|
278
|
+
memorio.devtools.inspect()
|
|
279
|
+
|
|
280
|
+
// Get stats
|
|
281
|
+
memorio.devtools.stats() // { stateKeys, storeKeys, sessionKeys, ... }
|
|
282
|
+
|
|
283
|
+
// Clear specific module
|
|
284
|
+
memorio.devtools.clear('state')
|
|
285
|
+
|
|
286
|
+
// Clear all modules
|
|
287
|
+
memorio.devtools.clearAll()
|
|
288
|
+
|
|
289
|
+
// Export all data as JSON
|
|
290
|
+
memorio.devtools.exportData()
|
|
291
|
+
|
|
292
|
+
// Import data from JSON
|
|
293
|
+
memorio.devtools.importData(jsonString)
|
|
294
|
+
|
|
295
|
+
// Show help
|
|
296
|
+
memorio.devtools.help()
|
|
297
|
+
|
|
298
|
+
// Console shortcuts
|
|
299
|
+
$state // same as globalThis.state
|
|
300
|
+
$store // same as globalThis.store
|
|
301
|
+
$session // same as globalThis.session
|
|
302
|
+
$cache // same as globalThis.cache
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### `logger` — Change Tracking
|
|
306
|
+
|
|
307
|
+
Track every state change with timestamps.
|
|
308
|
+
|
|
309
|
+
```javascript
|
|
310
|
+
// Configure logger
|
|
311
|
+
memorio.logger.configure({
|
|
312
|
+
enabled: true,
|
|
313
|
+
logToConsole: true,
|
|
314
|
+
modules: ['state', 'store', 'session', 'cache', 'idb']
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
// Get history
|
|
318
|
+
memorio.logger.getHistory() // [{ timestamp, module, action, path, value }, ...]
|
|
319
|
+
|
|
320
|
+
// Get stats
|
|
321
|
+
memorio.logger.getStats() // { total, state, store, session, cache, idb, set, get, ... }
|
|
322
|
+
|
|
323
|
+
// Clear history
|
|
324
|
+
memorio.logger.clearHistory()
|
|
325
|
+
|
|
326
|
+
// Export logs
|
|
327
|
+
memorio.logger.exportLogs() // JSON string of all history
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
## Platform Detection
|
|
331
|
+
|
|
332
|
+
Access via `memorio.*` after `import 'memorio'`:
|
|
333
|
+
|
|
334
|
+
```javascript
|
|
335
|
+
memorio.isBrowser() // true in Chrome, Firefox, Safari
|
|
336
|
+
memorio.isNode() // true in Node.js
|
|
337
|
+
memorio.isDeno() // true in Deno
|
|
338
|
+
memorio.isEdge() // true in Cloudflare Workers, Vercel Edge
|
|
339
|
+
|
|
340
|
+
const caps = memorio.getCapabilities()
|
|
341
|
+
// { platform: 'browser', hasLocalStorage: true, hasIndexedDB: true, sessionId: 'uuid', ... }
|
|
342
|
+
|
|
343
|
+
// Create isolated context
|
|
344
|
+
memorio.createContext('tenant-name')
|
|
345
|
+
memorio.listContexts()
|
|
346
|
+
memorio.deleteContext('context-id')
|
|
347
|
+
memorio.isolate('tenant-name') // alias for createContext
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
## Cross-Platform Support
|
|
351
|
+
|
|
352
|
+
| Module | Browser | Node.js | Deno | Edge/Workers |
|
|
353
|
+
|--------|---------|---------|------|--------------|
|
|
354
|
+
| `state` | ✅ | ✅ | ✅ | ✅ |
|
|
355
|
+
| `observer` / `useObserver` | ✅ | ✅ | ✅ | ✅ |
|
|
356
|
+
| `cache` | ✅ | ✅ | ✅ | ✅ |
|
|
357
|
+
| `store` | ✅ localStorage | ⚠️ memory | ⚠️ memory | ✅ localStorage |
|
|
358
|
+
| `session` | ✅ sessionStorage | ⚠️ memory | ⚠️ memory | ✅ sessionStorage |
|
|
359
|
+
| `idb` | ✅ IndexedDB | ❌ | ❌ | ⚠️ |
|
|
360
|
+
| `devtools` | ✅ | ❌ | ❌ | ⚠️ |
|
|
361
|
+
|
|
362
|
+
**Note:** `store` and `session` fall back to in-memory `Map` in Node.js/Deno.
|
|
363
|
+
|
|
364
|
+
## Session Isolation
|
|
365
|
+
|
|
366
|
+
Each browser tab and server request gets an isolated namespace automatically via session IDs.
|
|
367
|
+
|
|
368
|
+
```javascript
|
|
369
|
+
// Create isolated context
|
|
370
|
+
memorio.createContext('tenant-name')
|
|
371
|
+
memorio.listContexts()
|
|
372
|
+
memorio.deleteContext('context-id')
|
|
373
|
+
memorio.isolate('tenant-name') // alias for createContext
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## Security
|
|
377
|
+
|
|
378
|
+
- Zero production dependencies
|
|
379
|
+
- NIST & NSA aligned security standards
|
|
380
|
+
- No `eval`, no obfuscation, no hardcoded secrets
|
|
381
|
+
- All inputs validated, keys sanitized
|
|
382
|
+
- Secure random session IDs via `crypto.randomUUID`
|
|
383
|
+
|
|
384
|
+
## License
|
|
385
|
+
|
|
386
|
+
MIT © Dario Passariello (BigLogic Inc Canada)
|
|
387
|
+
|
|
388
|
+
## Utilities
|
|
389
|
+
|
|
390
|
+
### `memorio.dispatch` — Event Dispatch System
|
|
391
|
+
|
|
392
|
+
Internal event system used by state changes.
|
|
393
|
+
|
|
394
|
+
```javascript
|
|
395
|
+
// Dispatch a custom event
|
|
396
|
+
memorio.dispatch.set('custom:event', { detail: { data: 'value' } })
|
|
397
|
+
|
|
398
|
+
// Listen for an event
|
|
399
|
+
memorio.dispatch.listen('custom:event', (e) => {
|
|
400
|
+
console.debug('Event triggered:', e.detail)
|
|
401
|
+
})
|
|
402
|
+
|
|
403
|
+
// Remove listener
|
|
404
|
+
memorio.dispatch.remove('custom:event')
|
|
405
|
+
```
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Cache - Memorio
|
|
2
|
+
|
|
3
|
+
> ✅ **Universal**: Works in Browser, Node.js, Deno, and Edge Workers
|
|
4
|
+
|
|
5
|
+
Cache provides in-memory storage with a simple API. Data is lost on page refresh or process restart.
|
|
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 Usage
|
|
22
|
+
|
|
23
|
+
```javascript
|
|
24
|
+
// Save data
|
|
25
|
+
cache.set('username', 'Mario');
|
|
26
|
+
cache.set('score', 1500);
|
|
27
|
+
|
|
28
|
+
// Read data
|
|
29
|
+
console.debug(cache.get('username')); // "Mario"
|
|
30
|
+
console.debug(cache.get('score')); // 1500
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Example 2: Intermediate
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
// Store objects
|
|
37
|
+
cache.set('user', { name: 'Luigi', level: 5 });
|
|
38
|
+
const user = cache.get('user');
|
|
39
|
+
console.debug(user.name); // "Luigi"
|
|
40
|
+
|
|
41
|
+
// Remove single item
|
|
42
|
+
cache.remove('username');
|
|
43
|
+
|
|
44
|
+
// Clear all cache
|
|
45
|
+
cache.removeAll();
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## API Reference
|
|
51
|
+
|
|
52
|
+
### Methods
|
|
53
|
+
|
|
54
|
+
| Method | Parameters | Returns | Description |
|
|
55
|
+
|--------|------------|---------|-------------|
|
|
56
|
+
| `cache.get(name)` | `name: string` | `any` | Get value from cache |
|
|
57
|
+
| `cache.set(name, value)` | `name: string, value: any` | `void` | Save value to cache |
|
|
58
|
+
| `cache.remove(name)` | `name: string` | `boolean` | Remove single item |
|
|
59
|
+
| `cache.removeAll()` | `none` | `boolean` | Clear all cache |
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Storage Comparison
|
|
64
|
+
|
|
65
|
+
| Feature | Cache | Store | Session | IDB |
|
|
66
|
+
|---------|-------|-------|---------|-----|
|
|
67
|
+
| Platform Support | All (universal) | Browser/Edge | Browser/Edge | Browser only |
|
|
68
|
+
| Lifetime | Until refresh | Forever | Until tab closes | Forever |
|
|
69
|
+
| Capacity | Unlimited | ~5-10 MB | ~5-10 MB | 50+ MB |
|
|
70
|
+
| Use case | Temporary data | User preferences | Auth tokens | Large data |
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Platform Support
|
|
75
|
+
|
|
76
|
+
| Platform | Support | Notes |
|
|
77
|
+
|----------|---------|-------|
|
|
78
|
+
| Browser | ✅ Full | In-memory, lost on refresh |
|
|
79
|
+
| Node.js | ✅ Full | In-memory, lost on restart |
|
|
80
|
+
| Deno | ✅ Full | In-memory, lost on restart |
|
|
81
|
+
| Edge Workers | ✅ Full | In-memory, lost on function cold start |
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Best Practices
|
|
86
|
+
|
|
87
|
+
1. Use for temporary data that doesn't need persistence
|
|
88
|
+
2. Great for computed values or API response caching
|
|
89
|
+
3. Data is lost on page refresh - don't use for important data
|
|
90
|
+
4. Clear with `cache.removeAll()` when no longer needed
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Changelog - Memorio
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## v4.6.1 (Security Patch) - 2026-08-14 — CRITICAL Security Fix
|
|
8
|
+
|
|
9
|
+
### 🔐 Security NOTICE (v4.6.0)
|
|
10
|
+
|
|
11
|
+
**CRITICAL**: A Gitea Personal Access Token was accidentally committed to `.npmrc` in v4.6.0
|
|
12
|
+
|
|
13
|
+
**Affected**: `v4.6.0` tag and all builds from that version
|
|
14
|
+
|
|
15
|
+
**Action Required**:
|
|
16
|
+
- **IMMEDIATE**: Revoke ALL tokens on Gitea Packages by admin access
|
|
17
|
+
- **GENERATE**: Create new PAT with scope `write:package` only
|
|
18
|
+
- **CONFIGURE**: Add as secret `PAT` in GitHub Actions or Gitea Actions
|
|
19
|
+
- **UPGRADE**: Use v4.6.1 where the token is replaced with `${PAT}` environment variable
|
|
20
|
+
|
|
21
|
+
The hardcoded token `2f398d5d7a734781e96108fdd0dbbabad41ef77a` has been removed in v4.6.1.
|
|
22
|
+
|
|
23
|
+
### 🐛 Bug Fixes
|
|
24
|
+
|
|
25
|
+
- **SECURITY**: Removed hardcoded Gitea PAT from `.npmrc` (exposed token remediated)
|
|
26
|
+
- Replaced with environment variable `${PAT}` for secure authentication
|
|
27
|
+
|
|
28
|
+
### 📝 Documentation Updates
|
|
29
|
+
|
|
30
|
+
- `.npmrc`: Token replaced with environment variable reference
|
|
31
|
+
- `.gitea/workflows/npm.yml`: Configured to use secrets `GITEA_USER` and `PAT`
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## v4.6.0 (Previous - SECURITY ISSUE) - 2026-08-13 — Refactoring & Documentation
|
|
36
|
+
|
|
37
|
+
**⚠️ WARNING**: This version had a hardcoded PAT token that was later remediated in v4.6.1**
|
|
38
|
+
|
|
39
|
+
### 🐛 Bug Fixes
|
|
40
|
+
|
|
41
|
+
- Fixed circular import in `idb/index.ts` → `core/global`
|
|
42
|
+
- Fixed dead `globalThis._propertyAccessLog` reference in `observer`
|
|
43
|
+
- Fixed `dispatch.remove(f)` tuple bug in `functions/dispatch.ts`
|
|
44
|
+
- Fixed `logger.isDebugEnabled` using wrong module reference
|
|
45
|
+
- Removed dead `propertyAccessLog` / `pushPropertyAccess` from `core/internal.ts`
|
|
46
|
+
- Removed duplicate path-tracking block in `state` get handler
|
|
47
|
+
- Removed redundant `?? key` fallback in `state` set handler
|
|
48
|
+
|
|
49
|
+
### 🔧 Code Refactoring
|
|
50
|
+
|
|
51
|
+
- **Self-contained modules**: All modules now work independently without internal `globalThis.memorio.*` reads/writes
|
|
52
|
+
- **Module-local state**: Created `core/internal.ts` for module-local singletons
|
|
53
|
+
- **Bootstrap-only global**: `core/global.ts` now only publishes to `globalThis.memorio` at initialization
|
|
54
|
+
- **Removed dead code**: `core/constructor.ts` deleted (unused)
|
|
55
|
+
- **Extracted helpers**: `_read`/`_write`/`_remove` in `store` and `session` to eliminate duplication
|
|
56
|
+
- **Fixed circular imports**: `dispatch` → `observer` via `globalThis.events`
|
|
57
|
+
|
|
58
|
+
### 📝 Documentation Updates
|
|
59
|
+
|
|
60
|
+
- `docs/README.md`: Added Classic `import { state } from 'memorio'` section, improved badges layout, enhanced "Why memorio?" comparison table
|
|
61
|
+
- `docs/markdown/STORE.md`: Added classic import note
|
|
62
|
+
- `docs/markdown/IMPORT.md`: New file for named export guide
|
|
63
|
+
- `docs/SUMMARY.md`: Updated to include `IMPORT.md`
|
|
64
|
+
- `README.md`: Badge corrections, header cleanup, removed unverified bundle size claims
|
|
65
|
+
|
|
66
|
+
### 🆕 GitHub Actions / Gitea Workflows
|
|
67
|
+
|
|
68
|
+
- Added `.gitea/workflows/npm.yml` for automatic npm package publishing to Gitea Packages on `v*` tags
|
|
69
|
+
- Requires `GITEA_USER` and `PAT` secrets
|
|
70
|
+
|
|
71
|
+
### 🧪 Tests
|
|
72
|
+
|
|
73
|
+
- **Result: 9 suites · 101 passed · 4 skipped · 1 todo**
|
|
74
|
+
- All lint and typecheck clean
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## v3.0.2 (Current) - 2026-05-19 — Bug Fix, Security & API Expansion
|
|
79
|
+
|
|
80
|
+
### 🐛 Bug Fixes
|
|
81
|
+
|
|
82
|
+
- Removed dead code: `buildPathTracker` from `functions/state/index.ts` (unused Proxy builder, exported nowhere)
|
|
83
|
+
- Removed double `delete` in state `removeAll` handler (redundant null-check + delete on same key)
|
|
84
|
+
- Removed unbound `globalThis.state` reference in state init (would throw `ReferenceError` in strict mode)
|
|
85
|
+
- Removed `Object.freeze(observer)` referencing undeclared variable (`ReferenceError` on module load)
|
|
86
|
+
- Removed `confirm()` synchronous blocking call from `idb.db.delete` (library must not block main thread)
|
|
87
|
+
|
|
88
|
+
### 🔒 Security Improvements
|
|
89
|
+
|
|
90
|
+
- Removed `esbuild-sass-plugin` and `esbuild-scss-modules-plugin` from `devDependencies` (unnecessary for a library with no styles)
|
|
91
|
+
- Removed `injectStyle: true`, `sassPlugin()` and `.css` loader from `tsup.config.ts`
|
|
92
|
+
- Deleted `tsup.plugin.injectCss.ts` (code injection vector completely removed from build pipeline)
|
|
93
|
+
- `console.error`/`console.warn` → `console.debug` in `devtools` and `idb` error handlers (consistent debug-only logging policy)
|
|
94
|
+
- `store.set()` now blocks function values instead of silently logging and continuing
|
|
95
|
+
- All `PRIVATE License` headers in `functions/idb/` replaced with `MIT License`
|
|
96
|
+
|
|
97
|
+
### 🔧 Code Quality
|
|
98
|
+
|
|
99
|
+
- Added JSDoc to `observerFunction` in `functions/observer/index.ts`
|
|
100
|
+
- Added JSDoc to `cache` global in `functions/cache/index.ts`
|
|
101
|
+
- `lint` and `tsc` pass clean — 0 vulnerabilities from `npm audit`
|
|
102
|
+
|
|
103
|
+
### 🆕 API — New in 3.0.2
|
|
104
|
+
|
|
105
|
+
| Function | Description |
|
|
106
|
+
|----------|-------------|
|
|
107
|
+
| `memorio.isBrowser()` | Returns `true` when running in a browser |
|
|
108
|
+
| `memorio.isNode()` | Returns `true` when running in Node.js |
|
|
109
|
+
| `memorio.isDeno()` | Returns `true` when running in Deno |
|
|
110
|
+
| `memorio.isEdge()` | Returns `true` in Cloudflare Workers, Vercel Edge, etc. |
|
|
111
|
+
| `memorio.getCapabilities()` | Full capabilities object (`platform`, `hasLocalStorage`, `hasIndexedDB`, …) |
|
|
112
|
+
| `memorio.createContext(name?)` | Create multi-tenant isolated context |
|
|
113
|
+
| `memorio.listContexts()` | List all active isolated contexts |
|
|
114
|
+
| `memorio.deleteContext(id)` | Delete isolated context by ID |
|
|
115
|
+
| `memorio.isolate(name?)` | Shorthand alias for `createContext` |
|
|
116
|
+
|
|
117
|
+
### 🧪 Tests
|
|
118
|
+
- **Result: 8 suites · 95 passed · 3 skipped · 0 failed**
|
|
119
|
+
|
|
120
|
+
### 🗑️ Dependency Changes
|
|
121
|
+
|
|
122
|
+
| Removed | Reason |
|
|
123
|
+
|---------|--------|
|
|
124
|
+
| `esbuild-sass-plugin@3.7.0` | No SCSS in a library |
|
|
125
|
+
| `esbuild-scss-modules-plugin@1.1.1` | No SCSS in a library |
|
|
126
|
+
| 36 transitive packages | Removed from `node_modules` |
|
|
127
|
+
|
|
128
|
+
### 📝 Documentation Updates
|
|
129
|
+
|
|
130
|
+
- `docs/README.md`: replaced `console.debug` with `console.debug` in usage examples; fixed `esbuild` badge → `tsup`
|
|
131
|
+
- `.github/CHANGELOG.md`: restructured with fix / security / changed sections
|
|
132
|
+
- `.github/HISTORY.md`: complete rewrite through v3.0.2
|
|
133
|
+
- `.github/SECURITY.md`: NIST/NSA standard + OWASP Top 10 mapping
|
|
134
|
+
- `.github/CITATION.cff`: license PRIVATE → MIT to match `package.json`
|
|
135
|
+
- `.project/*`: all context documents updated to v3.0.2
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## v2.9.0 — 2026-05-13
|
|
140
|
+
|
|
141
|
+
### Added
|
|
142
|
+
- DevTools — `memorio.devtools.inspect()`, `stats()`, `exportData()`
|
|
143
|
+
- Logger with full history, stats and export
|
|
144
|
+
- Platform detection (`isBrowser`, `isNode`, `isDeno`, `isEdge`, `getCapabilities`)
|
|
145
|
+
- Session isolation via `crypto.randomUUID()`
|
|
146
|
+
|
|
147
|
+
### Changed
|
|
148
|
+
- Updated dependencies to latest versions
|
|
149
|
+
- Improved cross-platform support (Deno, Edge Workers, Node.js)
|
|
150
|
+
|
|
151
|
+
### Security
|
|
152
|
+
- Secure random session IDs replaced `Math.random()`
|
|
153
|
+
- Key validation (max 512 chars + character whitelist)
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## v2.5.0 — 2026-02-17
|
|
158
|
+
|
|
159
|
+
- Initial release of memorio (state, store, session, cache, idb)
|
|
160
|
+
- Observer pattern (`observer`)
|
|
161
|
+
- `useObserver` React hook
|