@kushalst/local-storage-expiry
v0.1.2
Published
A vanilla TypeScript wrapper for localStorage that adds TTL and lightweight XOR+Base64 obfuscation.
Maintainers
Readme
local-storage-expiry
Vanilla TypeScript wrapper for localStorage that adds:
- TTL (Time-To-Live) expiration per key
- Lightweight obfuscation (Unicode-safe XOR + Base64) so values aren’t stored as plain JSON
This package has zero runtime dependencies.
Install
npm i @kushalst/local-storage-expiryQuick start
import {
set,
get,
remove,
flushExpired,
clear,
} from "@kushalst/local-storage-expiry";
set("myKey", { hello: "world" }, 60_000); // expires in 60s
set("myKeyForever", { hello: "world" }); // persisted (no TTL)
const value = get<{ hello: string }>("myKey");
remove("myKey");
flushExpired();
clear(); // removes only keys created by this library (prefix: lse_)Key behavior (namespace)
All keys written by this library are stored under the localStorage key:
lse_${key}
So:
set("token", "abc", 1000)stores underlse_tokenset("token", "abc")stores underlse_token(no TTL)
This also means:
clear()removes only keys starting withlse_(it won’t touch other app keys)
API
All functions automatically apply the lse_ prefix.
set(key, value, ttlInMs?)
Store a value that expires after ttlInMs milliseconds. If ttlInMs is omitted, the value is persisted (never expires).
set("profile", { id: 123, name: "Kushal" }, 5 * 60_000);
set("profile", { id: 123, name: "Kushal" });- key:
string(stored aslse_${key}) - value:
unknown(must be JSON-serializable) - ttlInMs:
number(milliseconds, optional)
Notes:
- Expiry is computed using
Date.now() + ttlInMs.
get<T>(key): T | null
Read a value.
const profile = get<{ id: number; name: string }>("profile");Returns:
- The stored value if present and not expired
nullif missing, expired, or tampered/malformed
Important:
- If the entry is expired,
get()will remove it and returnnull. - If the entry is tampered/malformed,
get()will remove it and returnnull.
remove(key)
Remove a single key (only lse_${key}).
remove("profile");flushExpired()
Scan all localStorage keys and remove expired lse_ entries.
flushExpired();Behavior:
- Only keys starting with
lse_are considered - Expired entries are deleted
- Malformed/tampered entries are also deleted (to keep storage tidy)
- Non-
lse_keys are untouched
clear()
Remove only keys starting with lse_.
clear();Obfuscation (XOR + Base64)
This library does not store plain JSON in localStorage. Instead it:
- Serializes
{ v, e, d }as JSON (v=version,e=expiry epoch ms ornullfor “no expiry”,d=data) - UTF-8 encodes the JSON (so Unicode is safe)
- XORs bytes with a static internal secret
- Base64 encodes the result
This provides light obfuscation so data is not casually readable in DevTools.
Security note
This is not encryption and should not be used to protect secrets against a determined attacker. If you need real security, store sensitive data server-side or use proper cryptography and key management.
TTL / time notes
- Expiration uses the system clock via
Date.now(). - If the device clock changes, expiration behavior changes accordingly.
flushExpired()uses a singlenow = Date.now()snapshot for the entire sweep.
SSR / non-browser environments
This package uses localStorage. In environments where localStorage doesn’t exist (SSR, some Node contexts),
calling set/get/remove/flushExpired/clear will throw:
"localStorage is not available in this environment."
Common patterns:
if (typeof window !== "undefined") {
set("k", "v", 1000);
}Testing
The included test suite uses Vitest fake timers to validate TTL behavior.
If you test code that depends on expiration, prefer fake timers + vi.setSystemTime(...) for deterministic tests.
License
MIT
