A shared, persistent in-memory object database that works across multiple browser tabs or windows in the same session.
Built with a SharedWorker to synchronize data between clients.
How it Works
- Store.js – the browser-facing API.
Exposes an async-friendlyStore.Objectclass with methods likeget,put,add, etc. - StoreWorker.js – the backing SharedWorker.
Holds all data in memory, indexed by store IDs, and keeps it shared across all connected tabs. - Communication happens via
postMessage.
Each API call is wrapped in a Promise. The Worker responds with eitherresolveorreject. - Events (
created,changed,deleted) are broadcast to all clients.
API
All methods are async and return Promises.
| Method | Usage | Description |
|---|---|---|
add(val, key?) | Add value | Adds under key, or auto-generates one |
put(key, val) | Set value | Assigns at key (supports nested paths) |
get(key) | Get value | Reads at key (supports nested paths) |
remove(key) | Delete | Removes entry at key or nested path |
has(key) | Exists? | Checks if a key or path exists |
clear() | Wipe | Removes all keys |
size() | Count | Number of top-level keys |
keys() | List keys | Returns array of keys |
values() | List values | Returns array of values |
insert(i, ...v) | Insert at index | Inserts values in pseudo-ordered fashion |
Usage
Events
Store.on("created", e => console.log("Store created:", e.data));
Store.on("deleted", e => console.log("Store deleted:", e.data));
Store.on("changed", e => console.log("Store changed:", e.data));
Create or Reuse a Store
const clientId = "my-client";
const storeId = "my-store";
// Check if it already exists
let myStore = await Store.exists(storeId);
// Create if not
if (!myStore) {
myStore = await Store.create({
type: "object",
id: storeId,
client: clientId
});
}
Basic Operations
await myStore.put("a", 10);
await myStore.put("nested.value", { foo: 123 });
console.log(await myStore.get("a")); // 10
console.log(await myStore.get("nested.value")); // { foo: 123 }
console.log(await myStore.has("a")); // true
console.log(await myStore.keys()); // ["a", "nested"]
Manage Stores
console.log(await Store.instances());
// → [{ id: "my-store", type: "object", clients: ["my-client"], owner: "my-client" }]
await Store.delete(storeId);
console.log(await Store.exists(storeId)); // false
Internals
Each store in the Worker looks like:
{
id: "my-store",
type: "object",
data: {}, // actual key-value data
clients: ["clientId"], // connected clients
owner: "clientId" // creator
}
The Worker verifies that the clientId matches the MessagePort used when first registered.
This prevents spoofing across tabs.