A lightweight, dependency-free global store with persistence, hydration, and subscription support — designed for React Native and Web environments.
It lets you manage multiple namespaces (like theme, user, settings, etc) and persist them easily using your own storage backend.
- ✅ Multi-namespace store management (
AppStore.use("theme"),AppStore.use("user")) - 💾 Persistent data via pluggable storage adapter
- 🔁 Auto hydration (load from storage)
- 👂 Reactive subscriptions with
subscribe()andonHydrated() - ⚙️ Custom logging and debounced persistence
- 🔒 Works with encrypted or plain storage
npm install @chainplatform/appstoreor
yarn add @chainplatform/appstoreYou must configure your storage adapter once before using any stores.
import AppStore from "@chainplatform/appstore";
import { saveStorage, retrieveStorage, removeStorage } from "@chainplatform/sdk";
const customStorage = {
get: async (key) => await retrieveStorage(key, { encrypted: true }),
set: async (key, val) => await saveStorage(key, val, { encrypted: true }),
remove: async (key) => await removeStorage(key, { encrypted: true }),
};
// Configure once at app startup
AppStore.configure({
storage: customStorage,
log: true, // or false, or a custom logger function
});// Create or access a store
const themeStore = AppStore.use("theme", { encrypted: true });
// Hydrate data from persistent storage
await themeStore.hydrate();
// Subscribe to changes
const unsubscribe = themeStore.subscribe((newVal, oldVal) => {
console.log("Theme changed:", newVal);
});
// Set data
themeStore.set({ mode: "dark", primary: "#3498db" });
// Clear only in-memory data
themeStore.clear();
// Clear both in-memory and storage
await themeStore.clearStorage();
// Unsubscribe when needed
unsubscribe();const userStore = AppStore.use("user");
const drawerStore = AppStore.use("drawer");
// Load all stores in parallel
await AppStore.hydrateAll();
// Clear all memory data (not storage)
AppStore.clearAll();Configure global settings for all stores.
Should be called once, usually at app startup.
| Option | Type | Description |
|---|---|---|
storage |
{ get, set, remove } |
Custom async storage adapter |
log |
boolean | function |
Enables or overrides logging (default: false) |
Create or get a store by namespace.
| Param | Type | Description |
|---|---|---|
namespace |
string |
Unique key for store (e.g. "theme", "user") |
Returns a SingleStore instance.
| Method | Description |
|---|---|
hydrate() |
Load stored data and mark as hydrated |
subscribe(cb, { fireImmediately? }) |
Listen for data changes |
onHydrated(cb) |
Called once when hydration completes |
set(data) |
Set data |
clear() |
Clear in-memory data |
clearStorage() |
Clear both in-memory and persistent storage |
value |
Current store value |
initialized |
Whether the store has been hydrated |
You can pass a logger function or enable default console logging:
AppStore.configure({
storage: customStorage,
log: (msg, ...args) => console.debug("[AppStore]", msg, ...args),
});
// or simply:
AppStore.configure({ storage: customStorage, log: true });All log messages include namespace tags like [theme] hydrated.
- Call
AppStore.configure()only once globally — all stores share the same storage and logger. - Each store persists independently using its own
namespacekey. - To reset everything quickly:
AppStore.clearAll(); await customStorage.remove("theme"); await customStorage.remove("user");
import AppStore from "../src/helpers/AppStore";
describe("AppStore", () => {
const mockStorage = {
get: jest.fn(async () => JSON.stringify({ theme: "dark" })),
set: jest.fn(async () => {}),
remove: jest.fn(async () => {}),
};
beforeAll(() => {
AppStore.configure({ storage: mockStorage, log: false });
});
it("hydrates and sets data", async () => {
const store = AppStore.use("theme");
await store.hydrate();
expect(store.value).toEqual({ theme: "dark" });
store.set({ theme: "light" });
expect(store.value.theme).toBe("light");
});
});MIT © 2025 Chain Platform
If you find this package helpful, consider supporting the development:
Your contribution helps maintain open-source development under the Chain Platform ecosystem 🚀


