README.md
May 31, 2026 · View on GitHub
__ __ __ __
____ /\ \__ ___ /\ \/ \ __ /\ \ ___
/ ,__\ \ \ ,_\ / __`\ \ \ < /'__`\ \_\ \ / __`\
/\__, `\ \ \ \/ /\ \_\ \ \ \ ^ \ /\ \_\.\_ /\ ,. \ /\ \_\ \
\/\____/ \ \ \_ \ \____/ \ \_\ \_\\ \__/.\_\\ \____\\ \____/
\/___/ \ \__\ \/___/ \/_/\/_/ \/__/\/_/ \/___ / \/___/
\/__/
Stokado(/stəˈkɑːdoʊ/) is the Esperanto(an international auxiliary language) for storage, meaning that Stokado is also an auxiliary agent for storage.
stokado can proxy objects of any storage-like, providing getter/setter syntax sugars, serialization, subscription listening, expiration setting, one-time value retrieval.
The most feature-rich proxy wrapper for browser storage — serialization, reactivity, expiration, and one-time values in one library.
Why stokado?
| Feature | stokado | store2 | local-storage-fallback | lz-string |
|---|---|---|---|---|
| Proxy syntax sugar | ✅ | ❌ | ❌ | ❌ |
| Type-safe serialization | ✅ | ❌ | ❌ | ❌ |
| Reactive subscribe | ✅ | ❌ | ❌ | ❌ |
| Expiration | ✅ | ✅ | ❌ | ❌ |
| Disposable values | ✅ | ❌ | ❌ | ❌ |
| Async storage support | ✅ | ❌ | ❌ | ❌ |
| Cross-tab sync | ✅ | ❌ | ❌ | ❌ |
| Quota alert | ✅ | ❌ | ❌ | ❌ |
| Zero dependencies | ✅ | ✅ | ✅ | ✅ |
When to use stokado
- Type preservation — You need localStorage values to keep their JavaScript type (number, boolean, Date, RegExp, etc.) instead of everything becoming a string
- Reactive storage — You need to listen for storage changes within the same tab (native
storageevent only fires cross-tab) - Auto-expiration — You need stored items to automatically expire and clean up (token management, cache strategies)
- One-time values — You need disposable values for cross-component or cross-page communication
- Cross-tab sync — You need real-time synchronization of storage changes across browser tabs
- Async backends — You need to work with async storage like localForage or IndexedDB wrappers with the same API
- Quota alert — You need to monitor storage usage and get notified when approaching storage limits, with the option to block writes that would exceed the quota
Usage
Install
npm install stokado
Proxy
import { createProxyStorage } from 'stokado'
const storage = createProxyStorage(localStorage)
storage.getItem('test')
createProxyStorage(storage[, options])
createProxyStorage takes two parameters: an object of storage-like and an optional options. The options object supports the following fields:
broadcast— Whether to syncstoragemodifications with other pages. Default istrueforlocalStorage,falseforsessionStorage.channel— The channel name for cross-tab sync. By default,localStorageuses'localStorage'as the channel name.quota— Storage size limit in bytes. When set, stokado tracks the size of all data written through the proxy and triggers a callback when the limit is exceeded.onQuotaExceeded— Callback function triggered when storage usage exceeds thequotalimit. Receives aQuotaInfoobject with{ current, limit, key, value }. Returnfalseto block the write, or any other value to allow it. Supports async callbacks.
Features
1. Syntax sugar
Operate storage directly through object-oriented approach
Of course, localStorage and sessionStorage are supported natively
const storage = createProxyStorage(localStorage)
storage.test = 'hello stokado'
storage.test // 'hello stokado'
delete storage.test
The storage also have the same methods and properties: key(), getItem(), setItem(), removeItem(), clear() and length.
2. Serializer
Keep the type of storage value unchanged
// number
storage.test = 0
storage.test === 0
// boolean
storage.test = false
storage.test === false
// undefined
storage.test = undefined
storage.test === undefined
// null
storage.test = null
storage.test === null
// object
storage.test = { hello: 'world' }
storage.test.hello === 'stokado'
// array
storage.test = ['hello']
storage.test.push('stokado')
storage.test.length // 2
// Date
storage.test = new Date('2000-01-01T00:00:00.000Z')
storage.test.getTime() === 946684800000
// RegExp
storage.test = /d(b+)d/g
storage.test.test('cdbbdbsbz')
// function
storage.test = function () {
return 'hello stokado!'
}
storage.test() === 'hello stokado!'
3. Subscribe
Subscribe to value changes
storage.on(key, callback)
storage.once(key, callback)
storage.off([[key], callback])
key: the name of the item to subscribe to. Supportobj.aforObjectandlist[0]forArray, and alsoArraylength.callback: the function to call when the item is changed. IncludesnewValueandoldValue.
Tips: For off, if a callback exists, it removes the trigger of the specified callback; otherwise, it removes all callbacks bound to the key; if the key is empty, it removes all listening callbacks.
4. Expired
Set expires for items
storage.setExpires(key, expires)
storage.getExpires(key)
storage.removeExpires(key)
key: the name of the item to set expires.expires: acceptstring、numberandDate.
5. Disposable
Get the value once, which can be used for communication through storage.
storage.setDisposable(key)
key:the name of the item to set disposable.
6. Options
Get expires and disposable configuration information for the specified item
storage.getOptions(key)
Set expires and disposable using setItem
storage.setItem(key, value, { expires, disposable })
7. Quota Alert
Monitor storage usage and get notified when approaching limits
import { createProxyStorage, MB } from 'stokado'
const storage = createProxyStorage(localStorage, {
quota: 5 * MB,
onQuotaExceeded({ current, limit, key }) {
console.warn(`Storage quota exceeded: ${current}/${limit} bytes, key: "${key}"`)
return false
}
})
storage.getUsage()
await storage.ready
quota: Storage size limit in bytes. UseKBandMBconstants for readability.onQuotaExceeded: Callback when the limit is exceeded. Receives{ current, limit, key, value }. Returnfalseto block the write.getUsage(): Returns{ current, limit }— the current usage and the configured limit.ready: APromisethat resolves when the size tracker has finished scanning existing keys. For sync storages, it resolves immediately.
Note: The size calculation is based on the UTF-8 byte size of the encoded envelope (key + value) actually stored in the underlying storage. This closely approximates but may not exactly match the browser's internal storage accounting.
Limitations:
- Quota tracking covers data written through the stokado proxy and pre-existing keys scanned at initialization.
- Direct writes to the underlying storage from the same tab (bypassing stokado) are not tracked and may cause actual usage to exceed the quota without triggering an alert.
- Cross-tab writes are tracked through the
storageevent when broadcast is enabled, but there may be a brief delay.
AI Coding Rules
If you're using AI coding tools (Cursor, Copilot, Windsurf, etc.), copy the rules from ai-rules/.cursorrules to your project root as .cursorrules to help your AI assistant follow stokado best practices.
Presets
Stokado provides preset StorageLike adapters for common storage targets, so you can use createProxyStorage directly without implementing the interface yourself.
Cookie
import { createProxyStorage } from 'stokado'
import { cookieStorage } from 'stokado/presets/cookie'
const storage = createProxyStorage(cookieStorage)
WeChat Mini Program
import { createProxyStorage } from 'stokado'
import { wechatStorage } from 'stokado/presets/wechat'
const storage = createProxyStorage(wechatStorage)
Async version:
import { wechatStorageAsync } from 'stokado/presets/wechat'
const storage = createProxyStorage(wechatStorageAsync)
Douyin Mini Program
import { douyinStorage, douyinStorageAsync } from 'stokado/presets/douyin'
Alipay Mini Program
import { alipayStorage, alipayStorageAsync } from 'stokado/presets/alipay'
uni-app
import { uniStorage, uniStorageAsync } from 'stokado/presets/uni-app'
React Native
React Native requires injecting the AsyncStorage instance:
import AsyncStorage from '@react-native-async-storage/async-storage'
import { createProxyStorage } from 'stokado'
import { createReactNativeStorage } from 'stokado/presets/react-native'
const storage = createProxyStorage(createReactNativeStorage(AsyncStorage))
Node.js
import { createProxyStorage } from 'stokado'
import { memoryStorage } from 'stokado/presets/node'
const storage = createProxyStorage(memoryStorage)
Work with localForage
localForage provides the same API as localStorage, it can be used in conjunction with stokado.
import localForage from 'localforage'
import { createProxyStorage } from 'stokado'
const local = createProxyStorage(localForage, { channel: 'localForage' })
However, localForage uses an async API, it needs to be called using Promise.
await (local.test = 'hello localForage')
// or
await local.setItem('test', 'hello localForage')
Multiple instances
You can create multiple instances of localForage that point to different stores using createInstance.
const store = localforage.createInstance({
name: 'nameHere'
})
const proxyStore = createProxyStorage(store, { channel: 'store' })
const otherStore = localforage.createInstance({
name: 'otherName'
})
const proxyOtherStore = createProxyStorage(otherStore, { channel: 'otherStore' })
Keywords
stokado is a localStorage wrapper, browser storage proxy, web storage library, and storage utility for JavaScript. It provides localStorage serialization, storage reactivity, storage subscription, storage expiration, storage quota alert, cross-tab storage sync, and async storage support. Alternatives to store2, lscache, local-storage-fallback. Works with localStorage, sessionStorage, localForage, and any storage-like object.