Shared In-Memory Store (Store.js + StoreWorker.js)

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-friendly Store.Object class with methods like get, 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 either resolve or reject.
  • Events (created, changed, deleted) are broadcast to all clients.

API

All methods are async and return Promises.

MethodUsageDescription
add(val, key?)Add valueAdds under key, or auto-generates one
put(key, val)Set valueAssigns at key (supports nested paths)
get(key)Get valueReads at key (supports nested paths)
remove(key)DeleteRemoves entry at key or nested path
has(key)Exists?Checks if a key or path exists
clear()WipeRemoves all keys
size()CountNumber of top-level keys
keys()List keysReturns array of keys
values()List valuesReturns array of values
insert(i, ...v)Insert at indexInserts 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.