memorio
v4.7.0
Published
Memorio, State + Observer, Store and iDB for an easy life - Cross-platform compatible
Downloads
2,839
Maintainers
Readme
🧠 memorio
State + Observer + Store + IDB. One import. Zero config.
Memorio is a universal, cross-platform state management library for JavaScript and TypeScript. Reactive state, persistent store, session cache, IndexedDB, observer system, React hook, devtools, and logger — all from one import, zero dependencies.
✨ Why memorio?
| Feature | 🔥 memorio | Redux | Zustand |
|---|---|---|---|
| Setup | ✅ 1 import | ❌ Boilerplate hell | ⚠️ Moderate |
| Dependencies | ✅ Zero | ❌ Many | ⚠️ Few |
| TypeScript | ✅ Native | ✅ Yes | ✅ Yes |
| Binary storage | ✅ Built-in IDB | ❌ Add-on | ❌ Add-on |
| Observer | ✅ Built-in | ❌ Add-on | ❌ Add-on |
| DevTools | ✅ Built-in + dphelper-manager | ⚠️ Extension | ⚠️ Extension |
| Edge runtime | ✅ Workers, Deno | ❌ Limited | ❌ Limited |
| Learning curve | ✅ 5 minutes | ❌ Hours | ⚠️ 30 min |
| Boilerplate | ✅ None | ❌ Tons | ⚠️ Some |
| React support | ✅ useObserver hook | ✅ connect | ✅ useSyncExternalStore |
| Context isolation | ✅ Multi-tenant | ⚠️ Manual | ⚠️ Manual |
Zero dependencies. Lightweight. One import.
🚀 Features
| | |
|---|---|
| state | Reactive, Proxy-based volatile state |
| store | localStorage persistence (survives refresh) |
| session | sessionStorage (dies with tab) |
| cache | In-memory fastest cache |
| idb | IndexedDB with typed tables, structured and async |
| observer | Legacy object watcher for vanilla JS |
| useObserver | React hook with auto-discovery |
| dispatch | Event system: listen, emit, subscribe |
| devtools | Inspect everything in console |
| logger | Auto-log every state change with timestamps |
| Context isolation | Per-request / multi-tenant namespace |
| Platform detection | isBrowser, isNode, isDeno, isEdge |
No Zustand. No Redux. No provider boilerplate. Import → assign → done.
📦 Installation
# npm
npm i memorio
# pnpm
pnpm add memorio
# yarn
yarn add memorio
# React peer dep (optional, React >= 16.8)
npm i react react-dom🎯 Quick Start
Global style (original)
// import 'memorio' once at your app entry point
import 'memorio'
// state is now available everywhere
state.user = { name: 'Sara', role: 'admin' }
state.counter++
state.settings = { theme: 'dark', lang: 'it' }
// React - automatic dependency discovery
useObserver(
() => { console.debug('user changed:', state.user) },
[state.user]
)
// Vanilla JS - event system
memorio.dispatch.listen('state.user', (event) => {
console.debug('user changed:', event.detail)
})Classic import style (new)
Every module is also a named export. Same instances, explicit dependencies.
// ESM
import {
state,
store,
session,
cache,
idb,
observer,
useObserver,
dispatch,
memorio
} from 'memorio'
state.user = { name: 'Sara' }
store.set('theme', 'dark')
// CJS
const { state, store, memorio } = require('memorio')// React with named imports
import { useObserver, state } from 'memorio'
function Counter() {
const [, forceUpdate] = useReducer(x => x + 1, 0)
useObserver(forceUpdate, [state.counter])
return <div>Count: {state.counter}</div>
}Both styles share the exact same instances. Pick whichever fits your project.
📚 API Reference
state — Reactive volatile state
Global, Proxy-based, reactive. Access anywhere.
// Set
state.user = { name: 'Sara', role: 'admin' }
state.items = [1, 2, 3]
// Get
const name = state.user.name // 'Sara'
// List all keys
console.debug(state.list) // ['user', 'items']
// Remove one key
state.remove('items')
// Clear all
state.removeAll()
// Lock/unlock (prevents modifications)
state.config = { maxUsers: 100 }
state.config.lock()
state.config.maxUsers = 200 // Error: state 'config' is locked
state.config.unlock()store — Survives refresh
store.set('preferences', { theme: 'dark' })
const prefs = store.get('preferences') // { theme: 'dark' } or null
store.remove('preferences')
store.removeAll()
console.debug(store.size(), 'chars stored')
console.debug(store.isPersistent) // true -> real localStoragesession — Dies with tab
session.set('token', 'user-abc-123')
const token = session.get('token') // 'user-abc-123' or null
session.removeAll()cache — In-memory, disappears on refresh
cache.set('temp', computeExpensiveResult())
const result = cache.get('temp') // undefined or the value
cache.clear() // empty it allidb — Structured & typed
await idb.db.create('my-db')
await idb.table.create('my-db', 'users')
await idb.data.set('my-db', 'users', { id: 1, name: 'Sara' })
const user = await idb.data.get('my-db', 'users', 1)observer — Object watcher (legacy)
observer('state.user', (newVal, oldVal) => {
console.debug('user changed:', newVal, oldVal)
})useObserver — React observer hook
import { useObserver, state } from 'memorio'
function Counter() {
const [, forceUpdate] = useReducer(x => x + 1, 0)
useObserver(forceUpdate, [state.counter])
return <div>Count: {state.counter}</div>
}dispatch — Event system
// Listen
memorio.dispatch.listen('state.user', (event) => {
console.debug('user changed:', event.detail)
})
// Emit
memorio.dispatch.set('state.user', { detail: { name: 'state.user' } })
// Remove
memorio.dispatch.remove('state.user')devtools — Inspect everything
memorio.devtools.inspect() // pretty-prints state, store, session, cache
memorio.devtools.stats() // { stateKeys, storeKeys, sessionKeys, ... }
memorio.devtools.clear('state')
memorio.devtools.exportData() // JSON snapshot
$state // console shortcut -> globalThis.state💡 Browser Extension: When used with dphelper-manager, Memorio's global state is automatically detected and visualized with time-travel debugging.
logger — Track every change
memorio.logger.configure({ enabled: true, logToConsole: true })
memorio.logger.getHistory() // [{ timestamp, module, action, path, value }, ...]
memorio.logger.getStats() // { total, state, set, get, ... }
memorio.logger.exportLogs() // JSON string of all history🌍 Platform detection
memorio.isBrowser() // true in Chrome, Firefox, Safari
memorio.isNode() // true in Node.js
memorio.isDeno() // true in Deno
memorio.isEdge() // true in Cloudflare Workers, Vercel Edge
const caps = memorio.getCapabilities()
// { platform: 'browser', hasLocalStorage: true, hasIndexedDB: true, ... }Named exports work too:
import { isBrowser, isNode, getCapabilities } from 'memorio'🏢 Context isolation (multi-tenant)
// Create isolated context
const ctx = memorio.createContext('tenant-123')
// Use context storage (prefix: 'tenant-123-key')
ctx.state.user = { name: 'Isolated' }
ctx.store.set('settings', { theme: 'dark' })
ctx.session.set('token', 'abc123')
// Context is completely isolated from global state
console.debug(state.user) // undefined
// Manage contexts
memorio.listContexts() // ['tenant-123']
memorio.deleteContext('tenant-123')Named exports:
import { createContext, listContexts, deleteContext, isolate } from 'memorio'🖥️ Cross-Platform
Memorio runs in every JavaScript environment, with automatic fallbacks.
| Tool | Browser | Node.js | Deno | Edge / Workers |
|---|---|---|---|---|
| state | ✅ | ✅ | ✅ | ✅ |
| observer / useObserver | ✅ | ✅ | ✅ | ✅ |
| cache | ✅ | ✅ | ✅ | ✅ |
| store | localStorage | memory | memory | localStorage |
| session | sessionStorage | memory | memory | sessionStorage |
| idb | IndexedDB | ❌ | ❌ | ⚠️ |
| devtools | ✅ | ❌ | ❌ | ⚠️ |
Why memory fallbacks on the server? There is no browser.
storeandsessiongracefully fall back toMap. You still get the same API. Samestate, samecache, sameuseObserver. No extra config required.
🔒 Security
- Zero production dependencies — no supply chain surprises
- NIST & NSA aligned — enterprise-grade security standards
- No
eval, no obfuscation, no hardcoded secrets - All inputs validated, keys sanitized, errors caught
- Secure random session IDs via
crypto.randomUUID
📄 License
MIT © Dario Passariello
