memorio 4.1.0 → 4.1.6
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/index.cjs +31 -18
- package/index.js +31 -18
- package/llms.txt +405 -0
- package/package.json +1 -1
- package/types/observer.d.ts +1 -1
package/index.cjs
CHANGED
|
@@ -323,7 +323,7 @@ Object.defineProperty(globalThis, "memorio", {
|
|
|
323
323
|
}), Object.defineProperty(memorio, "version", {
|
|
324
324
|
writable: !1,
|
|
325
325
|
enumerable: !1,
|
|
326
|
-
value: "4.1.
|
|
326
|
+
value: "4.1.6"
|
|
327
327
|
}), Object.defineProperty(memorio, "debug", {
|
|
328
328
|
writable: !0,
|
|
329
329
|
enumerable: !1,
|
|
@@ -392,7 +392,10 @@ Object.defineProperty(memorio, "_sessionId", {
|
|
|
392
392
|
},
|
|
393
393
|
listen: (e, t = null, o = !1) => {
|
|
394
394
|
globalThis.observer?.list?.[e]?.length > 0 && globalThis.observer?.remove?.(e);
|
|
395
|
-
const r = t ? e =>
|
|
395
|
+
const r = t ? e => {
|
|
396
|
+
const o = e;
|
|
397
|
+
return globalThis.queueMicrotask ? globalThis.queueMicrotask(() => t(o)) : Promise.resolve().then(() => t(o));
|
|
398
|
+
} : void 0;
|
|
396
399
|
r && globalThis.addEventListener(e, r), r && (globalThis.events[e] = r);
|
|
397
400
|
},
|
|
398
401
|
remove: e => {
|
|
@@ -621,7 +624,7 @@ globalThis.observer = (e, t = null, o = !0) => {
|
|
|
621
624
|
|
|
622
625
|
var W = x(), R = new Map, U = null !== W, K = "memorio_store_";
|
|
623
626
|
|
|
624
|
-
function
|
|
627
|
+
function q(e) {
|
|
625
628
|
return e && "string" == typeof e ? e.length > 512 ? (memorio.message("Key too long (max 512 characters)"),
|
|
626
629
|
"") : /^[a-zA-Z0-9_.-]+$/.test(e) ? K + e : (memorio.message("Key contains invalid characters (only a-z, A-Z, 0-9, _, ., - allowed)"),
|
|
627
630
|
"") : "";
|
|
@@ -635,7 +638,7 @@ Object.defineProperty(globalThis, "store", {
|
|
|
635
638
|
get: {
|
|
636
639
|
value: e => {
|
|
637
640
|
if (!e) return;
|
|
638
|
-
const t =
|
|
641
|
+
const t = q(e);
|
|
639
642
|
try {
|
|
640
643
|
if (U) {
|
|
641
644
|
const e = W.getItem(t);
|
|
@@ -651,10 +654,20 @@ Object.defineProperty(globalThis, "store", {
|
|
|
651
654
|
return null;
|
|
652
655
|
}
|
|
653
656
|
},
|
|
657
|
+
getMultiple: {
|
|
658
|
+
value: e => {
|
|
659
|
+
const t = {};
|
|
660
|
+
for (const o of e) try {
|
|
661
|
+
const e = store.get(o);
|
|
662
|
+
e && (t[o] = e);
|
|
663
|
+
} catch {}
|
|
664
|
+
return t;
|
|
665
|
+
}
|
|
666
|
+
},
|
|
654
667
|
set: {
|
|
655
668
|
value: (e, t) => {
|
|
656
669
|
if (!e) return;
|
|
657
|
-
const o =
|
|
670
|
+
const o = q(e);
|
|
658
671
|
try {
|
|
659
672
|
if (U) {
|
|
660
673
|
if (null == t) W.setItem(o, JSON.stringify(null)); else if ("object" == typeof t || "number" == typeof t || "boolean" == typeof t || "string" == typeof t) W.setItem(o, JSON.stringify(t)); else if ("function" == typeof t) return void memorio.message("Storing functions is not secure and is blocked for safety.");
|
|
@@ -668,7 +681,7 @@ Object.defineProperty(globalThis, "store", {
|
|
|
668
681
|
remove: {
|
|
669
682
|
value: e => {
|
|
670
683
|
if (!e) return;
|
|
671
|
-
const t =
|
|
684
|
+
const t = q(e);
|
|
672
685
|
try {
|
|
673
686
|
if (U) {
|
|
674
687
|
if (W.getItem(t)) return W.removeItem(t), !0;
|
|
@@ -749,7 +762,7 @@ Object.defineProperty(globalThis, "store", {
|
|
|
749
762
|
}
|
|
750
763
|
}), Object.freeze(store);
|
|
751
764
|
|
|
752
|
-
var
|
|
765
|
+
var F = D(), L = new Map, H = null !== F, V = "memorio_session_";
|
|
753
766
|
|
|
754
767
|
function Y(e) {
|
|
755
768
|
return e && "string" == typeof e ? e.length > 512 ? (memorio.message("Key too long (max 512 characters)"),
|
|
@@ -768,7 +781,7 @@ Object.defineProperty(globalThis, "session", {
|
|
|
768
781
|
const t = Y(e);
|
|
769
782
|
try {
|
|
770
783
|
if (H) {
|
|
771
|
-
const e =
|
|
784
|
+
const e = F.getItem(t);
|
|
772
785
|
return e ? JSON.parse(e) : e;
|
|
773
786
|
}
|
|
774
787
|
{
|
|
@@ -785,7 +798,7 @@ Object.defineProperty(globalThis, "session", {
|
|
|
785
798
|
if (!e) return;
|
|
786
799
|
const o = Y(e);
|
|
787
800
|
try {
|
|
788
|
-
H ? null == t ?
|
|
801
|
+
H ? null == t ? F.setItem(o, JSON.stringify(null)) : "object" == typeof t || "number" == typeof t || "boolean" == typeof t || "string" == typeof t ? F.setItem(o, JSON.stringify(t)) : "function" == typeof t && memorio.message("It's not secure to session functions.") : null == t ? L.set(o, JSON.stringify(null)) : "object" == typeof t || "number" == typeof t || "boolean" == typeof t || "string" == typeof t ? L.set(o, JSON.stringify(t)) : "function" == typeof t && memorio.message("It's not secure to session functions.");
|
|
789
802
|
} catch (t) {
|
|
790
803
|
memorio.message(`Error setting session item '${e}': ${t}`);
|
|
791
804
|
}
|
|
@@ -797,7 +810,7 @@ Object.defineProperty(globalThis, "session", {
|
|
|
797
810
|
const t = Y(e);
|
|
798
811
|
try {
|
|
799
812
|
if (H) {
|
|
800
|
-
if (
|
|
813
|
+
if (F.getItem(t)) return F.removeItem(t), !0;
|
|
801
814
|
} else if (L.has(t)) return L.delete(t), !0;
|
|
802
815
|
} catch (t) {
|
|
803
816
|
memorio.message(`Error removing session item '${e}': ${t}`);
|
|
@@ -811,11 +824,11 @@ Object.defineProperty(globalThis, "session", {
|
|
|
811
824
|
value: () => {
|
|
812
825
|
if (H) {
|
|
813
826
|
const e = [];
|
|
814
|
-
for (let t = 0; t <
|
|
815
|
-
const o =
|
|
827
|
+
for (let t = 0; t < F.length; t++) {
|
|
828
|
+
const o = F.key(t);
|
|
816
829
|
o?.startsWith(V) && e.push(o);
|
|
817
830
|
}
|
|
818
|
-
e.forEach(e =>
|
|
831
|
+
e.forEach(e => F.removeItem(e));
|
|
819
832
|
} else L.clear();
|
|
820
833
|
return !0;
|
|
821
834
|
}
|
|
@@ -829,9 +842,9 @@ Object.defineProperty(globalThis, "session", {
|
|
|
829
842
|
size: {
|
|
830
843
|
value: () => {
|
|
831
844
|
let e = 0;
|
|
832
|
-
return H ? Object.keys(
|
|
845
|
+
return H ? Object.keys(F).forEach(t => {
|
|
833
846
|
if (t.startsWith(V)) {
|
|
834
|
-
const o =
|
|
847
|
+
const o = F.getItem(t);
|
|
835
848
|
o && (e += o.length);
|
|
836
849
|
}
|
|
837
850
|
}) : L.forEach(t => {
|
|
@@ -846,10 +859,10 @@ Object.defineProperty(globalThis, "session", {
|
|
|
846
859
|
value: () => {
|
|
847
860
|
const e = {};
|
|
848
861
|
try {
|
|
849
|
-
if (H) for (let t = 0; t <
|
|
850
|
-
const o =
|
|
862
|
+
if (H) for (let t = 0; t < F.length; t++) {
|
|
863
|
+
const o = F.key(t);
|
|
851
864
|
if (o?.startsWith(V)) {
|
|
852
|
-
const t = o.replace(V, ""), r =
|
|
865
|
+
const t = o.replace(V, ""), r = F.getItem(o);
|
|
853
866
|
if (null !== r) try {
|
|
854
867
|
e[t] = JSON.parse(r);
|
|
855
868
|
} catch {
|
package/index.js
CHANGED
|
@@ -321,7 +321,7 @@ Object.defineProperty(globalThis, "memorio", {
|
|
|
321
321
|
}), Object.defineProperty(memorio, "version", {
|
|
322
322
|
writable: !1,
|
|
323
323
|
enumerable: !1,
|
|
324
|
-
value: "4.1.
|
|
324
|
+
value: "4.1.6"
|
|
325
325
|
}), Object.defineProperty(memorio, "debug", {
|
|
326
326
|
writable: !0,
|
|
327
327
|
enumerable: !1,
|
|
@@ -390,7 +390,10 @@ Object.defineProperty(memorio, "_sessionId", {
|
|
|
390
390
|
},
|
|
391
391
|
listen: (e, t = null, o = !1) => {
|
|
392
392
|
globalThis.observer?.list?.[e]?.length > 0 && globalThis.observer?.remove?.(e);
|
|
393
|
-
const r = t ? e =>
|
|
393
|
+
const r = t ? e => {
|
|
394
|
+
const o = e;
|
|
395
|
+
return globalThis.queueMicrotask ? globalThis.queueMicrotask(() => t(o)) : Promise.resolve().then(() => t(o));
|
|
396
|
+
} : void 0;
|
|
394
397
|
r && globalThis.addEventListener(e, r), r && (globalThis.events[e] = r);
|
|
395
398
|
},
|
|
396
399
|
remove: e => {
|
|
@@ -619,7 +622,7 @@ globalThis.observer = (e, t = null, o = !0) => {
|
|
|
619
622
|
|
|
620
623
|
var W = x(), R = new Map, U = null !== W, K = "memorio_store_";
|
|
621
624
|
|
|
622
|
-
function
|
|
625
|
+
function q(e) {
|
|
623
626
|
return e && "string" == typeof e ? e.length > 512 ? (memorio.message("Key too long (max 512 characters)"),
|
|
624
627
|
"") : /^[a-zA-Z0-9_.-]+$/.test(e) ? K + e : (memorio.message("Key contains invalid characters (only a-z, A-Z, 0-9, _, ., - allowed)"),
|
|
625
628
|
"") : "";
|
|
@@ -633,7 +636,7 @@ Object.defineProperty(globalThis, "store", {
|
|
|
633
636
|
get: {
|
|
634
637
|
value: e => {
|
|
635
638
|
if (!e) return;
|
|
636
|
-
const t =
|
|
639
|
+
const t = q(e);
|
|
637
640
|
try {
|
|
638
641
|
if (U) {
|
|
639
642
|
const e = W.getItem(t);
|
|
@@ -649,10 +652,20 @@ Object.defineProperty(globalThis, "store", {
|
|
|
649
652
|
return null;
|
|
650
653
|
}
|
|
651
654
|
},
|
|
655
|
+
getMultiple: {
|
|
656
|
+
value: e => {
|
|
657
|
+
const t = {};
|
|
658
|
+
for (const o of e) try {
|
|
659
|
+
const e = store.get(o);
|
|
660
|
+
e && (t[o] = e);
|
|
661
|
+
} catch {}
|
|
662
|
+
return t;
|
|
663
|
+
}
|
|
664
|
+
},
|
|
652
665
|
set: {
|
|
653
666
|
value: (e, t) => {
|
|
654
667
|
if (!e) return;
|
|
655
|
-
const o =
|
|
668
|
+
const o = q(e);
|
|
656
669
|
try {
|
|
657
670
|
if (U) {
|
|
658
671
|
if (null == t) W.setItem(o, JSON.stringify(null)); else if ("object" == typeof t || "number" == typeof t || "boolean" == typeof t || "string" == typeof t) W.setItem(o, JSON.stringify(t)); else if ("function" == typeof t) return void memorio.message("Storing functions is not secure and is blocked for safety.");
|
|
@@ -666,7 +679,7 @@ Object.defineProperty(globalThis, "store", {
|
|
|
666
679
|
remove: {
|
|
667
680
|
value: e => {
|
|
668
681
|
if (!e) return;
|
|
669
|
-
const t =
|
|
682
|
+
const t = q(e);
|
|
670
683
|
try {
|
|
671
684
|
if (U) {
|
|
672
685
|
if (W.getItem(t)) return W.removeItem(t), !0;
|
|
@@ -747,7 +760,7 @@ Object.defineProperty(globalThis, "store", {
|
|
|
747
760
|
}
|
|
748
761
|
}), Object.freeze(store);
|
|
749
762
|
|
|
750
|
-
var
|
|
763
|
+
var F = D(), L = new Map, H = null !== F, V = "memorio_session_";
|
|
751
764
|
|
|
752
765
|
function Y(e) {
|
|
753
766
|
return e && "string" == typeof e ? e.length > 512 ? (memorio.message("Key too long (max 512 characters)"),
|
|
@@ -766,7 +779,7 @@ Object.defineProperty(globalThis, "session", {
|
|
|
766
779
|
const t = Y(e);
|
|
767
780
|
try {
|
|
768
781
|
if (H) {
|
|
769
|
-
const e =
|
|
782
|
+
const e = F.getItem(t);
|
|
770
783
|
return e ? JSON.parse(e) : e;
|
|
771
784
|
}
|
|
772
785
|
{
|
|
@@ -783,7 +796,7 @@ Object.defineProperty(globalThis, "session", {
|
|
|
783
796
|
if (!e) return;
|
|
784
797
|
const o = Y(e);
|
|
785
798
|
try {
|
|
786
|
-
H ? null == t ?
|
|
799
|
+
H ? null == t ? F.setItem(o, JSON.stringify(null)) : "object" == typeof t || "number" == typeof t || "boolean" == typeof t || "string" == typeof t ? F.setItem(o, JSON.stringify(t)) : "function" == typeof t && memorio.message("It's not secure to session functions.") : null == t ? L.set(o, JSON.stringify(null)) : "object" == typeof t || "number" == typeof t || "boolean" == typeof t || "string" == typeof t ? L.set(o, JSON.stringify(t)) : "function" == typeof t && memorio.message("It's not secure to session functions.");
|
|
787
800
|
} catch (t) {
|
|
788
801
|
memorio.message(`Error setting session item '${e}': ${t}`);
|
|
789
802
|
}
|
|
@@ -795,7 +808,7 @@ Object.defineProperty(globalThis, "session", {
|
|
|
795
808
|
const t = Y(e);
|
|
796
809
|
try {
|
|
797
810
|
if (H) {
|
|
798
|
-
if (
|
|
811
|
+
if (F.getItem(t)) return F.removeItem(t), !0;
|
|
799
812
|
} else if (L.has(t)) return L.delete(t), !0;
|
|
800
813
|
} catch (t) {
|
|
801
814
|
memorio.message(`Error removing session item '${e}': ${t}`);
|
|
@@ -809,11 +822,11 @@ Object.defineProperty(globalThis, "session", {
|
|
|
809
822
|
value: () => {
|
|
810
823
|
if (H) {
|
|
811
824
|
const e = [];
|
|
812
|
-
for (let t = 0; t <
|
|
813
|
-
const o =
|
|
825
|
+
for (let t = 0; t < F.length; t++) {
|
|
826
|
+
const o = F.key(t);
|
|
814
827
|
o?.startsWith(V) && e.push(o);
|
|
815
828
|
}
|
|
816
|
-
e.forEach(e =>
|
|
829
|
+
e.forEach(e => F.removeItem(e));
|
|
817
830
|
} else L.clear();
|
|
818
831
|
return !0;
|
|
819
832
|
}
|
|
@@ -827,9 +840,9 @@ Object.defineProperty(globalThis, "session", {
|
|
|
827
840
|
size: {
|
|
828
841
|
value: () => {
|
|
829
842
|
let e = 0;
|
|
830
|
-
return H ? Object.keys(
|
|
843
|
+
return H ? Object.keys(F).forEach(t => {
|
|
831
844
|
if (t.startsWith(V)) {
|
|
832
|
-
const o =
|
|
845
|
+
const o = F.getItem(t);
|
|
833
846
|
o && (e += o.length);
|
|
834
847
|
}
|
|
835
848
|
}) : L.forEach(t => {
|
|
@@ -844,10 +857,10 @@ Object.defineProperty(globalThis, "session", {
|
|
|
844
857
|
value: () => {
|
|
845
858
|
const e = {};
|
|
846
859
|
try {
|
|
847
|
-
if (H) for (let t = 0; t <
|
|
848
|
-
const o =
|
|
860
|
+
if (H) for (let t = 0; t < F.length; t++) {
|
|
861
|
+
const o = F.key(t);
|
|
849
862
|
if (o?.startsWith(V)) {
|
|
850
|
-
const t = o.replace(V, ""), r =
|
|
863
|
+
const t = o.replace(V, ""), r = F.getItem(o);
|
|
851
864
|
if (null !== r) try {
|
|
852
865
|
e[t] = JSON.parse(r);
|
|
853
866
|
} catch {
|
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, deprecated |
|
|
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.log('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.log(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.log(store.size(), 'chars stored')
|
|
104
|
+
|
|
105
|
+
// Check if persistent (real localStorage vs memory fallback)
|
|
106
|
+
console.log(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.log(session.size(), 'chars stored')
|
|
140
|
+
|
|
141
|
+
// Check if persistent
|
|
142
|
+
console.log(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 (DEPRECATED)
|
|
219
|
+
|
|
220
|
+
Legacy observer API. Use `useObserver` instead.
|
|
221
|
+
|
|
222
|
+
```javascript
|
|
223
|
+
// Listen to state changes
|
|
224
|
+
observer('state.user', (newVal, oldVal) => {
|
|
225
|
+
console.log('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.log(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.log('counter:', state.counter)
|
|
255
|
+
}, state.counter)
|
|
256
|
+
|
|
257
|
+
// Explicit deps mode
|
|
258
|
+
useObserver(
|
|
259
|
+
() => { console.log('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.log('Event triggered:', e.detail)
|
|
401
|
+
})
|
|
402
|
+
|
|
403
|
+
// Remove listener
|
|
404
|
+
memorio.dispatch.remove('custom:event')
|
|
405
|
+
```
|
package/package.json
CHANGED