tiny-server-state
v0.1.4
Published
Lightweight TTL-enabled in-memory state for Node servers
Downloads
21
Maintainers
Readme
🧠 tiny-server-state
A lightweight, reactive in-memory state engine for Node.js servers. It offers simple key-value storage with optional TTL (Time-To-Live), real-time subscriptions, and a React-like API for easier state management.
Ideal for handling temporary, shared, or cacheable state without a database.
🚀 Features
- ✅ Simple and minimal state engine
- 🕓 TTL-based expiration (auto-deletes expired keys)
- 🧠 React-style
useStatefor intuitive state access - 📡 Subscriptions for real-time updates
- 🔁 Automatic Garbage Collection (GC)
- 🛠️ No external dependencies
- 🔒 TypeScript support out of the box
📦 Installation
npm install tiny-server-state🚀 Quick Start
import { createServerState } from "tiny-server-state";
// Create a new state store instance
const store = createServerState();
// Use React-like state management
const [count, setCount] = store.useState("count", 0);
console.log(count); // 0
// Update state with a new value
setCount(5);
// Or use a function to update based on previous value
setCount(prev => prev + 1);📚 API Reference
Creating a Store
const store = createServerState(sweepInterval?: number);sweepInterval: Optional interval (in ms) for garbage collection (default: 60000)
Core Methods
get<T>(key: string): T | undefined
Retrieve a value from the store.
const value = store.get("myKey");set<T>(key: string, value: T, options?: StateOptions): void
Set a value in the store.
// Simple set
store.set("myKey", "myValue");
// Set with TTL (expires after 5 seconds)
store.set("temporaryKey", "value", { ttl: 5000 });useState<T>(key: string, initial: T | (() => T), options?: StateOptions)
React-style state management.
// Basic usage
const [value, setValue] = store.useState("key", "initial");
// With initializer function
const [user, setUser] = store.useState("user", () => ({ name: "John" }));
// With TTL
const [token, setToken] = store.useState("token", "abc123", { ttl: 3600000 }); // 1 hour
// Update examples
setValue("new value"); // Direct update
setValue(prev => prev + " updated"); // Function updatesubscribe<T>(key: string, callback: (value: T) => void)
Subscribe to state changes.
// Subscribe to changes
const unsubscribe = store.subscribe("user", (newValue) => {
console.log("User updated:", newValue);
});
// Later: cleanup subscription
unsubscribe();useEffect(effect: () => void | (() => void), deps?: string[], effectId?: string)
React-style effect management for side effects when state changes.
// Run effect when dependencies change
const cleanup = store.useEffect(
() => {
console.log("User or settings changed");
// Optional cleanup function
return () => {
console.log("Effect cleanup");
};
},
["user", "settings"] // Dependencies
);
// Run effect only once (no dependencies)
const onceCleanup = store.useEffect(() => {
console.log("This runs once");
});
// Later: cleanup effect
cleanup();cacheCompute<T>(factory: () => T, deps: string[], cacheId?: string): T
Server-side alternative to React's useMemo. Memoizes a computed value based on dependencies. The value is recomputed only when dependencies change.
// Memoize an expensive computation based on dependencies
const result = store.cacheCompute(() => expensiveCalculation(a, b), ["a", "b"]);cacheCallback<T extends (...args: any[]) => any>(fn: T, deps: string[], callbackId?: string): T
Server-side alternative to React's useCallback. Memoizes a callback function based on dependencies. The function is recreated only when dependencies change.
// Memoize a callback function based on dependencies
const memoizedFn = store.cacheCallback(() => doSomething(a), ["a"]);cleanupAllEffects(): void
Cleanup all active effects (useful for testing or shutdown).
// Cleanup all effects at once
store.cleanupAllEffects();🎯 Use Cases
1. Session Management
// Store session data with automatic expiration
const [session, setSession] = store.useState("session", null, {
ttl: 30 * 60 * 1000 // 30 minutes
});
// Update session
setSession({ userId: "123", lastActive: Date.now() });2. Caching
// Cache expensive operation results
async function getCachedData(id: string) {
const [data, setData] = store.useState(`cache:${id}`, null, {
ttl: 5 * 60 * 1000 // 5 minutes
});
if (!data) {
const newData = await fetchExpensiveData(id);
setData(newData);
return newData;
}
return data;
}3. Real-time Updates and Side Effects
// Broadcast changes to all subscribers
const [status, setStatus] = store.useState("systemStatus", "operational");
const [metrics, setMetrics] = store.useState("metrics", { cpu: 0, memory: 0 });
// React to status and metrics changes
store.useEffect(() => {
const currentMetrics = store.get("metrics");
const currentStatus = store.get("systemStatus");
// Notify admins when system is stressed
if (currentMetrics.cpu > 90 || currentMetrics.memory > 90) {
notifyAdmins(`High resource usage detected! CPU: ${currentMetrics.cpu}%, Memory: ${currentMetrics.memory}%`);
setStatus("stressed");
}
// Log all status changes
console.log(`System status: ${currentStatus}`);
// Cleanup function (runs before next effect or on cleanup)
return () => {
console.log(`Previous status: ${currentStatus}`);
};
}, ["systemStatus", "metrics"]);
// Update status
setStatus("maintenance");
// Update metrics
setMetrics({ cpu: 95, memory: 85 }); // This will trigger the effect and change status to "stressed"🔧 Configuration
StateOptions Interface
interface StateOptions {
ttl?: number; // Time-to-live in milliseconds
}Garbage Collection
The store automatically removes expired entries at regular intervals. You can configure the sweep interval when creating the store:
// Custom sweep interval (e.g., every 5 minutes)
const store = createServerState(5 * 60 * 1000);🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
📄 License
MIT License - feel free to use this in your own projects.
🔍 TypeScript Support
This package includes TypeScript definitions out of the box. You'll get full type safety and autocompletion in your TypeScript projects.
// Type-safe state management
const [user, setUser] = store.useState<{
id: string;
name: string;
age: number;
}>("user", {
id: "1",
name: "John",
age: 30
});
// TypeScript will ensure type safety
setUser(prev => ({
...prev,
age: prev.age + 1
}));⚡ Performance Considerations
- The store uses an in-memory Map, so be mindful of memory usage when storing large objects
- TTL and garbage collection help manage memory automatically
- Consider using shorter TTLs for frequently changing data
- For large-scale applications, consider using a proper database instead
🔐 Security Notes
- Data is stored in memory and will be lost when the server restarts
- Don't store sensitive information without proper encryption
- Be cautious with TTL values to prevent memory leaks
- Consider implementing rate limiting for state updates if exposed to client requests
👨💻 About Me
Visit my portfolio: deodeepkunj.dev
📘 Blogs
Read my latest technical write-ups at Medium
