Persistent client-side storage, localStorage, sessionStorage, IndexedDB. Plain ESM module registered with createWorker({ mainThreadModules: { storage } }) (or the host field of packages.json); see host/README.md for the setup boilerplate.
from storage import local_set, local_get, idb_open, idb_put, idb_get
from "https://cdn.edgepython.com/std/json.wasm" import loads
local_set("theme", "dark")
print(local_get("theme")) # -> "dark"
db = idb_open("notes", 1, '{"stores":["items"]}')
idb_put(db, "items", "1", '{"title":"hello"}')
note = loads(idb_get(db, "items", "1"))deno run -A npm:playwright install chromium # one-time
HOSTCAP=storage deno test --allow-all tests/ # from repo rootSee tests/README.md for the corpus shape.
- KV handlers are sync.
localStorage/sessionStorageare blocking by spec; handlers return strings orNone. Noawait, noreceive(). - IndexedDB handlers yield. They return a Promise on the JS side; the runtime parks the coro in
WaitingHostCalluntil resolved, same shape asfetch()innetwork/. - Values cross as JSON strings. Encode with
json.dumps, decode withjson.loads. - Key listings are JSON arrays (keys can contain commas). Parse with
json.loads. - Handles are integer IDs for IndexedDB;
local_*/session_*address global stores directly (no handle).
local_get, local_set, local_remove, local_clear, local_keys. Same surface for sessionStorage with the session_ prefix (session_get, …). Difference is lifetime: sessionStorage clears when the tab closes; localStorage persists.
local_set("theme", "dark")
print(local_get("missing")) # -> None
print(loads(local_keys())) # -> ["theme"]
local_remove("theme")
local_clear()idb_open, idb_put, idb_get, idb_delete, idb_keys, idb_close.
# Schema declares the object stores to create on first open / version bump.
db = idb_open("notes", 1, '{"stores":["items","tags"]}')
idb_put(db, "items", "1", dumps({"title": "hello", "ts": 1234}))
item = loads(idb_get(db, "items", "1"))
keys = loads(idb_keys(db, "items"))
idb_close(db)Because IndexedDB handlers yield, they compose with the scheduler:
items, tags = gather(idb_keys(db, "items"), idb_keys(db, "tags")) # parallel reads
item = with_timeout(0.5, idb_get(db, "items", "1")) # deadlinesrc/index.js is a factory () => handlers (same shape as dom, network). Two slices in src/main/ (kv, idb) close over a shared state (a handle table for open IDBDatabase instances) and merge with Object.assign. KV handlers call localStorage / sessionStorage directly; IDB handlers promisify native IDBRequests and the runtime parks until resolved.
MIT OR Apache-2.0